/**
 * @file nb_main.c
 * @brief
 *
 * @version 0.1
 * @date 2023-09-08
 *
 * @copyright  Copyright (c) 2020~2030 ShenZhen dingxintongchuang Technology Co., Ltd.
 * All rights reserved.
 *
 * @note          鼎新同创・智能锁
 *
 * @par 修改日志:
 * <1> 2023-09-08 v0.1 tianshidong 创建初始版本
 * *************************************************************************
 */
#include "nb_main.h"
#include "debug_config.h"
#include "nb_comp.h"
#include "local_main.h"
#include "application.h"

#define CMD_TIMEOUT_SEC (30 * 60) //命令超时时间

static TimerHandle_stu_t nbSendResTimer = NULL;            // nb发送执行结果
static NB_delEvidence_store_stu_t storeEvidenceInfo = {0}; //测试用，临时存储凭证
static Nb_ueImportantPara_t nbUeParam;                     // UE关键状态参数

static void NbMain_creat_aes_key(uint8_t *macHex, uint8_t *imeiStr, uint8_t imeiLen, uint8_t macLen);
static uint8_t NBMain_delete_evidence(uint8_t delType, uint8_t delEvidId);
static uint8_t NBMain_add_evidence(uint8_t evidenceId, uint8_t *evidValue, uint8_t evidenceLen, uint32_t startTime, uint32_t endTime);
static void FuncNb_lkm3_report_alarm_info_Handle(uint32_t timeStamp, uint8_t alarmType, uint8_t userId);
static void FuncNb_lkm3_report_openLock_record_Handle(uint32_t timeStamp, uint8_t userId);
extern TestMode_enum_t ATE_GetProductionTestMode(void);
extern set_sleep_flag(uint8_t flag);
static void NbMain_upd_FourID(void);
static uint8_t getFourIdFlag = 0;
/**
 * @brief nv读取测试函数
 *
 *
 * @note
 */
static void nb_nv_read_test(void)
{
    uint8_t iemi[15] = {0};
    uint8_t iccid[20] = {0};
    uint8_t macAddr[6] = {0};
    uint8_t auth[8] = {0};
    uint8_t csq = 0;

    OSAL_NvRead(SYS_OFFSET(nbCSQ), &csq, sizeof(csq));
    OSAL_NvRead(SYS_OFFSET(nbAuthenticationCode), auth, sizeof(auth));
    OSAL_NvRead(SYS_OFFSET(nbIemi), iemi, sizeof(iemi));
    OSAL_NvRead(SYS_OFFSET(nbIccid), iccid, sizeof(iccid));
    OSAL_NvRead(SYS_OFFSET(bleMacAddr), macAddr, sizeof(macAddr));
    FUNC_NB_LOG_HEX("iemi", iemi, sizeof(iemi));
    FUNC_NB_LOG_HEX("iccid", iccid, sizeof(iccid));
    FUNC_NB_LOG_HEX("macAddr", macAddr, sizeof(macAddr));
    FUNC_NB_LOG_HEX("auth", auth, sizeof(auth));
    FUNC_NB_LOG_I("nb csq:%d", csq);
}

/**
 * @brief 发送云平台南向地址和端口号
 *
 *
 * @note
 */
static void NBMain_send_netInfo(void)
{
    uint8_t nbSouthIpAddr_port[20] = {0}; //前16个字节是南向地址，后4个字节是端口
    uint8_t defaultAddr[16] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    uint8_t defaultport[4] = {0xff, 0xff, 0xff, 0xff};

    OSAL_NvRead(SYS_OFFSET(nbSouthIpAddr), nbSouthIpAddr_port, 16);
    OSAL_NvRead(SYS_OFFSET(nbport), &nbSouthIpAddr_port[16], 4);

    if (memcmp(defaultAddr, nbSouthIpAddr_port, 16) == 0)
    {
        memcpy(nbSouthIpAddr_port, SOUTH_ADDRESS, strlen(SOUTH_ADDRESS));
    }
    if (memcmp(defaultport, &nbSouthIpAddr_port[16], 4) == 0)
    {
        memcpy(&nbSouthIpAddr_port[16], SOUTH_PORT, strlen(SOUTH_PORT));
    }

    FUNC_NB_LOG_HEX("nbSouthIpAddr:", nbSouthIpAddr_port, 16);
    FUNC_NB_LOG_HEX("port:", &nbSouthIpAddr_port[16], 4);

    Nb_SendNetInfoToNb(nbSouthIpAddr_port, sizeof(nbSouthIpAddr_port));
}
/**
 * @brief 激活时，超时函数
 *
 * @param [in] xTimer
 *
 * @note
 */
static void NB_sendResultCallback(TimerHandle_stu_t xTimer)
{
    nbSendResTimer = NULL;
    SYS_CALL(FuncBle_lkm3_activate_Handle, 0xEE18);
    uint8_t active = 1;
    OSAL_NvWrite(SYS_OFFSET(lockActiveFlag), &active, 1);
    if (getFourIdFlag)
    {
        getFourIdFlag = 0;
        NbMain_upd_FourID();
    }
}

/**
 * @brief 校验鉴权码
 *
 * @param [in] pAuth
 * @param [in] autthLen
 * @return uint8_t
 *
 * @note
 */
static uint8_t NbMain_auth_verify(uint8_t *pAuth, uint8_t authLen)
{
    uint8_t result = ERROR;
    uint8_t nbAuthCode[8] = {0};

    OSAL_NvRead(SYS_OFFSET(nbAuthenticationCode), nbAuthCode, sizeof(nbAuthCode));
    if (memcmp(nbAuthCode, pAuth, authLen) == 0)
    {
        result = SUCCESS;
    }
    else
    {
        FUNC_NB_LOG_HEX("nbAuthCode", nbAuthCode, sizeof(nbAuthCode));
        FUNC_NB_LOG_HEX("pAuth", pAuth, authLen);
        FUNC_NB_LOG_E("Verify authentication failed");
    }

    return result;
}

/**
 * @brief
 *
 * @param [in] pAuth
 * @param [in] authLen
 * @return uint8_t
 *
 * @note
 */
static uint8_t NbMain_time_verify(uint32_t timestaps)
{
    uint8_t curTime[6] = {0};
    uint32_t curTimeStamps = 0;
    uint32_t cmdInvalidTime = 0;
    uint8_t result = ERROR;

    cmdInvalidTime = OSAL_SWAP32(timestaps);

    OSAL_TimeGet(curTime, T_TIME);
    FUNC_NB_LOG_D("cur time :%d,%d,%d,%d,%d,%d\r\n", curTime[0], curTime[1], curTime[2], curTime[3], curTime[4], curTime[5]);
    OSAL_TimeGet(&curTimeStamps, T_UTC);
    FUNC_NB_LOG_D("cur timestamp :%d, Cmd invalid time:%d\r\n", curTimeStamps, cmdInvalidTime);

    if (cmdInvalidTime >= curTimeStamps)
    {
        result = SUCCESS;
    }
    else
    {
        FUNC_NB_LOG_W("CMD Time error");
    }
    return result;
}

/**
 * @brief 远程开锁上报
 *
 * @param [in] record
 * @return int
 *
 * @note
 */
static int Remote_RecordReport(EventRecord_stu_t *record)
{
    FUNC_NB_LOG_I("report open lock success, evidence id:%d, time:%d", record->userID, record->timestamp);

    if (record->eventType == EVENT_TYPE_OPEN_CLOSE)
    {
        if (record->eventCode == EVENT_CODE_UNLOCK)
        {
            SYS_CALL(FuncBle_lkm3_unLockSta_Handle, EVIDENCE_ACK_SUCCESS, record->userID, record->timestamp);
            // FuncNb_lkm3_report_openLock_record_Handle(record->timestamp, record->userID);//跟安居微堂的唐邵旺确认不需要上报开锁记录，有远程开门应答0x1F 即可
        }
    }
    else if (record->eventType == EVENT_TYPE_ALARM)
    {
        FuncNb_lkm3_report_alarm_info_Handle(record->timestamp, record->eventCode, record->userID);
    }
}

/**
 * @brief 控制模组 进入或者退出PSM模式
 *
 * @param [in] cmd NB_CONTROL_ENTER_PSM : 进入   NB_CONTROL_EXIT_PSM : 退出PSM
 *
 * @note
 */
static void NBMain_control_nb_psm_status(uint8_t cmd)
{
    uint8_t controlStatus = 0;

    controlStatus = cmd;
    Nb_SendCmdToNb(&controlStatus, sizeof(controlStatus));
}
/**
 * @brief 发送数据给云模组
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] len 数据长度
 * @param [in] data 协议中 cmd+data的长度
 *
 * @note
 */
static void NbMain_send_data_to_Nblot(uint16_t mid, uint8_t sid, uint16_t len, uint8_t *data)
{
    NbSendToLotMsg_t msg;

    memset(&msg, 0, sizeof(msg));

    msg.MID = mid;
    msg.SID = sid;
    msg.len = len;
    memcpy(msg.pData, data, len);

    Nb_SendDataToNb(&msg, len + 5);

    FUNC_NB_LOG_D("send_data_to_Nblot activeStatus:%d", SYS_CALL(BleMain_get_activeStatus));
    if (SYS_CALL(BleMain_get_activeStatus) == SET)
    {
        if (data[0] == NB_LKM3_CMD_SET_AES_KEY || data[0] == NB_LKM3_CMD_SET_AUTHENTICATION || data[0] == NB_LKM3_CMD_DEL_EVIDENCE)
        {
            //激活过程中，前三条指令不下发控制NB马上进入PSM的命令
            return;
        }
    }

    FUNC_NB_LOG_D("NB main control enter PSM, cmd:0x%x", data[0]);
    if (data[0] == NB_LKM3_CMD_NET_OPEN_LOCK && SYS_CALL(NB_TASK_Get_AepOtaMark) != SET)
    {
        NBMain_control_nb_psm_status(NB_CONTROL_ENTER_PSM_NOT_RAI);
    }
    else
    {
        // NBMain_control_nb_psm_status(NB_CONTROL_ENTER_PSM);
    }
}
/**
 * @brief 发送数据给AEP OTA
 *
 * @param [in] cmd
 * @param [in] len 数据长度
 * @param [in] data 协议中 data的长度
 *
 * @note
 */
static void NbMain_send_AepOtaData_to_NbIot(uint8_t cmd, uint16_t len, uint8_t *data)
{
    NbSendToAepOtaMsg_t msg;

    memset(&msg, 0, sizeof(msg));
    msg.cmd = cmd;
    msg.len = len;
    memcpy(msg.pData, data, len);
    Nb_SendAepOtaDataToNb(&msg, len + 3);
    FUNC_NB_LOG_D("AEP OTA: send data to AEP");
}
/**
 * @brief 发送唤醒数据给lot
 *
 * @param [in] operation 1:初始化密钥（自检必须要初始化密钥）  0：不初始化（除自检外的命令不许初始化密钥）
 * @return uint8_t
 *
 * @note
 */
static uint8_t NbMain_send_readData_cmd(uint8_t operation)
{
    FUNC_NB_LOG_D("Read nb lot data");
    uint8_t bleMac[6] = {0};
    uint8_t nbIMEI[15] = {0};

    if (operation)
    {
        OSAL_NvRead(SYS_OFFSET(bleMacAddr), bleMac, sizeof(bleMac));
        OSAL_NvRead(SYS_OFFSET(nbIemi), nbIMEI, sizeof(nbIMEI));

        NbMain_creat_aes_key(bleMac, nbIMEI, sizeof(nbIMEI), sizeof(bleMac));
        // Nb_SendCmdToNb(NULL, 0);
    }
    NBMain_control_nb_psm_status(NB_CONTROL_EXIT_PSM);
    OSAL_UpdateSleepTime(10000, 1);

    return 0;
}

static MessageCallback_fun_t pGetCsqCallback = NULL;
/**
 * @brief 获取NB设备的IEMI
 *
 * @param [in] cb
 * @return uint8_t
 *
 * @note
 */
static uint8_t NbMain_get_CSQ(MessageCallback_fun_t cb)
{
    pGetCsqCallback = cb;
    Nb_SendReadCsq(NULL, 0);
}
/**
 * @brief 构造初始的密钥
 *
 * @param [in] macHex
 * @param [in] iemiStr
 *
 * @note "mac + iemi +mac" 取前32个字符，转换为16进制串
 */
static void NbMain_creat_aes_key(uint8_t *macHex, uint8_t *imeiStr, uint8_t imeiLen, uint8_t macLen)
{
    uint8_t bleMacStr[12] = {0};
    uint8_t allStr[39] = {0};
    uint8_t bleMacStrLen = 0;
    uint8_t aesKey[16] = {0};

    bleMacStrLen = SYS_CALL(NB_TASK_hex_to_str, bleMacStr, macHex, macLen);

    memcpy(allStr, bleMacStr, bleMacStrLen);
    memcpy(&allStr[bleMacStrLen], imeiStr, imeiLen);
    memcpy(&allStr[bleMacStrLen + imeiLen], bleMacStr, bleMacStrLen);

    FUNC_NB_LOG_D("allStr:%.*s", 39, allStr);
    SYS_CALL(NB_TASK_str_to_hex, allStr, aesKey, 32);
    FUNC_NB_LOG_HEX("aesKey:", aesKey, sizeof(aesKey));

    Nb_SendAESToNb(aesKey, sizeof(aesKey));
}

static uint32_t ota_dataOffser = 0;
static int32_t packNextNum = 0;
/**
 * @brief 传输文件分包片
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_ota_file_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_otaFile_cmd_stu_t *pOtaFile = (NB_otaFile_cmd_stu_t *)pdata;
    NB_otaFile_ack_stu_t otaFileAck = {0};
    uint8_t result = OTA_WIRTE_ERR;
    uint16_t packNum = OSAL_SWAP16(pOtaFile->packNum);
    uint16_t packSize = OSAL_SWAP16(pOtaFile->packSize);
    FUNC_NB_LOG_D("OTA packNum:%d,packSize:%d", packNum, packSize);
    FUNC_NB_LOG_HEX("data:", pOtaFile->data, pOtaFile->packSize);
    if (packNum = packNextNum)
    {
        result = OTA_PACKNUM_ERR;
    }
    else
    {
        result = OTA_WIRTE_SUCC;
        SYS_CALL(McuOta_Task_Write, ota_dataOffser, pOtaFile->data, packSize);
        ota_dataOffser += packSize;
        packNextNum++;
    }

    otaFileAck.ackCmd = pOtaFile->cmd;
    otaFileAck.result = result;
    otaFileAck.packNum = pOtaFile->packNum;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(otaFileAck), (uint8_t *)&otaFileAck);
}
/**
 * @brief 传输结束确认
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_ota_transmit_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_otaEnd_cmd_stu_t *pOtaEnd = (NB_otaEnd_cmd_stu_t *)pdata;
    NB_otaEnd_ack_stu_t otaEndAck = {0};
    uint8_t result = OTA_CRC_ERR;
    uint16_t softVersion = OSAL_SWAP16(pOtaEnd->softVersion);
    uint16_t packNums = OSAL_SWAP16(pOtaEnd->packNums);

    FUNC_NB_LOG_D("OTA softVersion:%X,packNums:%d,packSize:%d", softVersion, packNums);
    if (SUCCESS == SYS_CALL(McuOtaCode_Check))
    {
        result = OTA_UPGTADE_SUCC;
        OSAL_SystemReset(3000);
        SYS_CALL(Set_SilentRest_flag, SET); //静默复位
    }
    else
    {
        result = OTA_CRC_ERR;
    }

    otaEndAck.ackCmd = pOtaEnd->cmd;
    otaEndAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(otaEndAck), (uint8_t *)&otaEndAck);
}
/**
 * @brief 升级请求
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_ota_request_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_otaReq_cmd_stu_t *pOtaReq = (NB_otaReq_cmd_stu_t *)pdata;
    NB_otaReq_ack_stu_t otaReqAck = {0};
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;
    uint16_t softVersion = OSAL_SWAP16(FIRMWARE_VERSION);
    if (NbMain_auth_verify(pOtaReq->Auth, sizeof(pOtaReq->Auth)) == SUCCESS)
    {
        otaReqAck.updResuit = OTA_ALLOWED_UPGTADE;
        result = EVIDENCE_ACK_SUCCESS;
    }
    packNextNum = 0;
    ota_dataOffser = 0;

    otaReqAck.ackCmd = pOtaReq->cmd;
    otaReqAck.result = result;
    otaReqAck.breakpoint = 0;
    otaReqAck.MaxSize = OSAL_SWAP16(OTA_MAX_SIZE);
    NbMain_send_data_to_Nblot(mid, sid, sizeof(otaReqAck), (uint8_t *)&otaReqAck);
}

/**
 * @brief 安装门锁完成
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_install_lock_complete_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_lockInstallComplete_cmd_stu_t *pInstallComplete = (NB_lockInstallComplete_cmd_stu_t *)pdata;
    NB_lockInstall_ack_stu_t installCompleteAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&installCompleteAck, 0, sizeof(installCompleteAck));

    if (NbMain_auth_verify(pInstallComplete->AuthVerify, sizeof(pInstallComplete->AuthVerify)) == SUCCESS)
    {
        //清空凭证信息
        result = NBMain_delete_evidence(DEL_ALL_EVIDENCE, 0);
        FUNC_NB_LOG_I("install_lock_complete\n\n\n");
        if (EVIDENCE_ACK_ERROR == result)
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
            FUNC_NB_LOG_I("install_lock_complete err\n\n\n");
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    installCompleteAck.ackCmd = pInstallComplete->cmd;
    installCompleteAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(installCompleteAck), (uint8_t *)&installCompleteAck);

    SYS_CALL(FuncBle_lkm3_general_ack_Handle, 0XBA24, result);
    FUNC_NB_LOG_W("install_lock_complete restart device  time Later:%d", 3000);
    OSAL_SystemReset(3000);
    SYS_CALL(Set_SilentRest_flag, SET); //静默复位
}

/**
 * @brief 安装门锁初始化
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_install_lock_info_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_lockInstall_cmd_stu_t *pInstallLock = (NB_lockInstall_cmd_stu_t *)pdata;
    NB_lockInstall_ack_stu_t installLockAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;
    uint8_t aesKey[16] = {0};

    memset(&installLockAck, 0, sizeof(installLockAck));

    FUNC_NB_LOG_I("set id:%d", pInstallLock->EvidenceID);
    FUNC_NB_LOG_HEX("verify auth:", pInstallLock->AuthVerify, sizeof(pInstallLock->AuthVerify));
    FUNC_NB_LOG_HEX("set key:", pInstallLock->key, sizeof(pInstallLock->key));
    FUNC_NB_LOG_HEX("set auth:", pInstallLock->AuthSet, sizeof(pInstallLock->AuthSet));
    FUNC_NB_LOG_HEX("set evidence:", pInstallLock->evidenceValue, sizeof(pInstallLock->evidenceValue));

    if (NbMain_auth_verify(pInstallLock->AuthVerify, sizeof(pInstallLock->AuthVerify)) == SUCCESS)
    {
        //清空凭证信息
        result = NBMain_delete_evidence(DEL_ALL_EVIDENCE, 0);
        FUNC_NB_LOG_I("FuncNb_lkm3_install_lock_info_Handle del all evidence\n\n\n");
        if (EVIDENCE_ACK_ERROR == result)
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
            FUNC_NB_LOG_I("FuncNb_lkm3_install_lock_info_Handle err\n\n\n");
        }
        else
        {
            //再添加一个凭证
            result = NBMain_add_evidence(pInstallLock->EvidenceID, pInstallLock->evidenceValue, sizeof(pInstallLock->evidenceValue), pInstallLock->startTimeStamp, pInstallLock->endTimeStamp);
            if(result == EVIDENCE_ACK_SUCCESS)
            {
                memcpy(aesKey, pInstallLock->key, sizeof(pInstallLock->key));
                OSAL_NvWrite(SYS_OFFSET(nbAuthenticationCode), pInstallLock->AuthSet, sizeof(pInstallLock->AuthSet));
                Nb_SendAESToNb(aesKey, sizeof(aesKey));
            }
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    installLockAck.ackCmd = pInstallLock->cmd;
    installLockAck.result = result;

    NbMain_send_data_to_Nblot(mid, sid, sizeof(installLockAck), (uint8_t *)&installLockAck);

    SYS_CALL(FuncBle_lkm3_general_ack_Handle, 0XBA23, result);
}

/**
 * @brief 查询本地凭证列表
 *
 * @param [in] evidenceList
 * @return uint8_t
 *
 * @note
 */
static uint8_t NBMain_inquiry_evidence_list(NB_EvidenceList_type_stu_t *pEvidenceList, uint8_t inquiryType, uint8_t *pEvidenceNum, uint8_t *pIdList)
{
    uint8_t evidenceTotolNum = 0;
    uint32_t curTimeStamps = 0;
    uint8_t keyId = 0;
    NB_NvEvidence_stu_t evidenceInfo = {0};
    evidenceTotolNum = SYS_CALL(Users_GetKeysQty, USERS_TYPE_EVIDENCE);
    OSAL_TimeGet(&curTimeStamps, T_UTC);

    FUNC_NB_LOG_I("Inquiry evidence, inquiryType:%d, Total num:%d, curTimeStamps:%d", inquiryType, evidenceTotolNum, curTimeStamps);

    for (keyId = 0; keyId <= evidenceTotolNum; keyId++)
    {
        if (SYS_CALL(Users_KeyNumIsExist, USERS_TYPE_EVIDENCE, keyId) == USERS_NUMBER_EXISTED)
        {
            if (SYS_CALL(Users_ReadKeys, USERS_TYPE_EVIDENCE, keyId, &evidenceInfo) == SUCCESS)
            {
                FUNC_NB_LOG_I("id:%d, keynum:%d", evidenceInfo.EvidenceId, keyId);
                FUNC_NB_LOG_I("status:%d", evidenceInfo.EvidenceStatus);
                FUNC_NB_LOG_I("stime:%d, 0x%x", evidenceInfo.stime, evidenceInfo.stime);
                FUNC_NB_LOG_I("etime:%d, 0x%x", evidenceInfo.etime, evidenceInfo.etime);
                FUNC_NB_LOG_HEX("value:", evidenceInfo.Evidence, sizeof(evidenceInfo.Evidence));
                switch (inquiryType)
                {
                case INQUIRY_ALL_EVIDENCE:
                {
                    pIdList[*pEvidenceNum] = evidenceInfo.EvidenceId;
                    pEvidenceList[*pEvidenceNum].evidenceID = evidenceInfo.EvidenceId;
                    memcpy(pEvidenceList[*pEvidenceNum].evidenceValue, evidenceInfo.Evidence, sizeof(pEvidenceList[*pEvidenceNum].evidenceValue));
                    pEvidenceList[*pEvidenceNum].openLockTimes = 0xff;
                    pEvidenceList[*pEvidenceNum].startTimeStamp = OSAL_SWAP32(evidenceInfo.stime);
                    pEvidenceList[*pEvidenceNum].endTimeStamp = OSAL_SWAP32(evidenceInfo.etime);
                    pEvidenceList[*pEvidenceNum].EvidenceStusus = evidenceInfo.EvidenceStatus;
                    *pEvidenceNum += 1;
                }
                break;

                case INQUIRY_FREEZE_EVIDENCE:
                {
                    if (evidenceInfo.EvidenceStatus == EVIDENCE_STATUS_FREEZE)
                    {
                        pIdList[*pEvidenceNum] = evidenceInfo.EvidenceId;
                        pEvidenceList[*pEvidenceNum].evidenceID = evidenceInfo.EvidenceId;
                        memcpy(pEvidenceList[*pEvidenceNum].evidenceValue, evidenceInfo.Evidence, sizeof(pEvidenceList[*pEvidenceNum].evidenceValue));
                        pEvidenceList[*pEvidenceNum].openLockTimes = 0xff;
                        pEvidenceList[*pEvidenceNum].startTimeStamp = OSAL_SWAP32(evidenceInfo.stime);
                        pEvidenceList[*pEvidenceNum].endTimeStamp = OSAL_SWAP32(evidenceInfo.etime);
                        pEvidenceList[*pEvidenceNum].EvidenceStusus = evidenceInfo.EvidenceStatus;
                        *pEvidenceNum += 1;
                    }
                }
                break;

                case INQUIRY_ACTIVE_EVIDENCE:
                {
                    if (evidenceInfo.EvidenceStatus == EVIDENCE_STATUS_ACTIVE)
                    {
                        pIdList[*pEvidenceNum] = evidenceInfo.EvidenceId;
                        pEvidenceList[*pEvidenceNum].evidenceID = evidenceInfo.EvidenceId;
                        memcpy(pEvidenceList[*pEvidenceNum].evidenceValue, evidenceInfo.Evidence, sizeof(pEvidenceList[*pEvidenceNum].evidenceValue));
                        pEvidenceList[*pEvidenceNum].openLockTimes = 0xff;
                        pEvidenceList[*pEvidenceNum].startTimeStamp = OSAL_SWAP32(evidenceInfo.stime);
                        pEvidenceList[*pEvidenceNum].endTimeStamp = OSAL_SWAP32(evidenceInfo.etime);
                        pEvidenceList[*pEvidenceNum].EvidenceStusus = evidenceInfo.EvidenceStatus;
                        *pEvidenceNum += 1;
                    }
                }
                break;

                case INQUIRY_VALID_EVIDENCE:
                {
                    if (curTimeStamps >= evidenceInfo.stime && curTimeStamps < evidenceInfo.etime)
                    {
                        pIdList[*pEvidenceNum] = evidenceInfo.EvidenceId;
                        pEvidenceList[*pEvidenceNum].evidenceID = evidenceInfo.EvidenceId;
                        memcpy(pEvidenceList[*pEvidenceNum].evidenceValue, evidenceInfo.Evidence, sizeof(pEvidenceList[*pEvidenceNum].evidenceValue));
                        pEvidenceList[*pEvidenceNum].openLockTimes = 0xff;
                        pEvidenceList[*pEvidenceNum].startTimeStamp = OSAL_SWAP32(evidenceInfo.stime);
                        pEvidenceList[*pEvidenceNum].endTimeStamp = OSAL_SWAP32(evidenceInfo.etime);
                        pEvidenceList[*pEvidenceNum].EvidenceStusus = evidenceInfo.EvidenceStatus;
                        *pEvidenceNum += 1;
                    }
                }
                break;

                case INQUIRY_INVALID_EVIDENCE:
                {
                    if (curTimeStamps < evidenceInfo.stime || curTimeStamps >= evidenceInfo.etime)
                    {
                        pIdList[*pEvidenceNum] = evidenceInfo.EvidenceId;
                        pEvidenceList[*pEvidenceNum].evidenceID = evidenceInfo.EvidenceId;
                        memcpy(pEvidenceList[*pEvidenceNum].evidenceValue, evidenceInfo.Evidence, sizeof(pEvidenceList[*pEvidenceNum].evidenceValue));
                        pEvidenceList[*pEvidenceNum].openLockTimes = 0xff;
                        pEvidenceList[*pEvidenceNum].startTimeStamp = OSAL_SWAP32(evidenceInfo.stime);
                        pEvidenceList[*pEvidenceNum].endTimeStamp = OSAL_SWAP32(evidenceInfo.etime);
                        pEvidenceList[*pEvidenceNum].EvidenceStusus = evidenceInfo.EvidenceStatus;
                        *pEvidenceNum += 1;
                    }
                }
                break;

                default:
                    break;
                }
            }
            else
            {
                return NB_LKM3_RESULT_PARAM_ERROR;
            }
        }
    }

    return NB_LKM3_RESULT_SUCCESS;
}

/**
 * @brief 查询凭证列表
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_inquiry_evidence_list_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    uint8_t evidenceTotalNum = 0; //已存储的总数量
    uint8_t reportNum = 0;        //查询需要上报的数量
    uint16_t ackLen = 0;
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;
    uint8_t idList[21] = {0};

    NB_inquiryEvidenceList_cmd_stu_t *pInquiryEvid = (NB_inquiryEvidenceList_cmd_stu_t *)pdata;
    NB_inquiryEvidenceList_ack_stu_t *pInquiryAck = NULL;

    if (NbMain_auth_verify(pInquiryEvid->Auth, sizeof(pInquiryEvid->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pInquiryEvid->failureTime) == SUCCESS)
        {
            evidenceTotalNum = SYS_CALL(Users_GetQty, USERS_TYPE_EVIDENCE, 1);
            ackLen = sizeof(NB_inquiryEvidenceList_ack_stu_t) + (sizeof(NB_EvidenceList_type_stu_t) * evidenceTotalNum);
            pInquiryAck = (NB_inquiryEvidenceList_ack_stu_t *)OSAL_Malloc(ackLen);
            if (pInquiryAck == NULL)
            {
                FUNC_NB_LOG_E("Inquiry evidence malloc error");
                return;
            }
            result = NBMain_inquiry_evidence_list(pInquiryAck->evidenceList, pInquiryEvid->evidenceType, &reportNum, idList);
        }
    }
    FUNC_NB_LOG_D("evidenceTotalNum:%d, reportNum:%d , ackLen:%d", evidenceTotalNum, reportNum, ackLen);
    FUNC_NB_LOG_HEX("idList:", idList, 20);

    pInquiryAck->ackCmd = pInquiryEvid->cmd;
    pInquiryAck->result = result;
    pInquiryAck->evidenceNum = reportNum;

    FUNC_NB_LOG_HEX("Iqr data:", pInquiryAck, ackLen);
    NbMain_send_data_to_Nblot(mid, sid, ackLen, (uint8_t *)pInquiryAck);

    SYS_CALL(FuncBle_lkm3_getEvidenceList_Handle, result, pInquiryEvid->evidenceType, reportNum, idList);

    OSAL_Free(pInquiryAck);
}

/**
 * @brief 查询配置信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_inquiry_config_info_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_inquiryConfigInfo_cmd_stu_t *pInquiryCfgInfo = (NB_inquiryConfigInfo_cmd_stu_t *)pdata;
    NB_inquiryConfigInfo_ack_stu_t inquiryCfgInfoAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&inquiryCfgInfoAck, 0, sizeof(inquiryCfgInfoAck));

    if (NbMain_auth_verify(pInquiryCfgInfo->Auth, sizeof(pInquiryCfgInfo->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pInquiryCfgInfo->failureTime) == SUCCESS)
        {
            memcpy(inquiryCfgInfoAck.southIpAddr, SOUTH_ADDRESS, strlen(SOUTH_ADDRESS));
            memset(&inquiryCfgInfoAck.southIpAddr[strlen(SOUTH_ADDRESS)], 0, 16 - strlen(SOUTH_ADDRESS));
            memcpy(inquiryCfgInfoAck.port, SOUTH_PORT, strlen(SOUTH_PORT));
            inquiryCfgInfoAck.lockRunMode = MODE_NORMAL;
            result = EVIDENCE_ACK_SUCCESS;
        }
        else
        {
            result = EVIDENCE_ACK_ERROR;
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    inquiryCfgInfoAck.ackCmd = pInquiryCfgInfo->cmd;
    inquiryCfgInfoAck.result = result;

    NbMain_send_data_to_Nblot(mid, sid, sizeof(inquiryCfgInfoAck), (uint8_t *)&inquiryCfgInfoAck);

    SYS_CALL(FuncBle_lkm3_inquiryConfig_Handle, result, inquiryCfgInfoAck.southIpAddr, inquiryCfgInfoAck.port, inquiryCfgInfoAck.lockRunMode);
}

/**
 * @brief 设置重启频次
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_restart_frequency_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_frequencyRestart_cmd_stu_t *pRestartFrequency = (NB_frequencyRestart_cmd_stu_t *)pdata;
    NB_frequencyRestart_ack_stu_t restartFrequencyAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&restartFrequencyAck, 0, sizeof(restartFrequencyAck));

    if (NbMain_auth_verify(pRestartFrequency->Auth, sizeof(pRestartFrequency->Auth)) == SUCCESS)
    {
        FUNC_NB_LOG_D("Restart frequency:%d", pRestartFrequency->softRestartFreq);

        uint16_t freq[RESTART_TIMES_MAX_TIMES] = {3, 5, 10, 20, 30};
        uint32_t cycle = (24 * 3600) / freq[pRestartFrequency->softRestartFreq];
        RtcAlarm_Set(RESTART_NAME, cycle, SET);
        OSAL_NvWrite(SYS_OFFSET(restartDevicePeriod), &pRestartFrequency->softRestartFreq, 1);
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    restartFrequencyAck.ackCmd = pRestartFrequency->cmd;
    restartFrequencyAck.result = result;

    NbMain_send_data_to_Nblot(mid, sid, sizeof(restartFrequencyAck), (uint8_t *)&restartFrequencyAck);

    SYS_CALL(FuncBle_lkm3_restertFre_Handle, result, pRestartFrequency->softRestartFreq);
}

/**
 * @brief 上报恢复出厂设置
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_report_reset_factory_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_reportResetFactory_cmd_stu_t resetFactory;

    memset(&resetFactory, 0, sizeof(resetFactory));

    resetFactory.cmd = NB_LKM3_CMD_REPORT_RESET_FACTORY;

    NbMain_send_data_to_Nblot(0, 0, sizeof(resetFactory), (uint8_t *)&resetFactory);
}

/**
 * @brief 报警类型转换
 *
 * @param [in] localType
 * @return uint8_t
 *
 * @note
 */
static uint8_t FuncNb_lkm3_alarm_type_convert(uint8_t localType)
{
    uint8_t nbType = 0;

    switch (localType)
    {
    case EVENT_CODE_PRY_LOCK:
        nbType = ALARM_TYPE_PRY_LOCK;
        break;

    case EVENT_CODE_LOW_POWER:
        nbType = ALARM_TYPE_BATTERY_LOW;
        break;

    case EVENT_CODE_HIJACK:
        nbType = ALARM_TYPE_HIJACK;
        break; 
    case EVENT_CODE_SYSLOCK:
        nbType = ALARM_TYPE_UNLOCK_EVIDENCE_TRY;
        break;
    default:
        break;
    }

    return nbType;
}
/**
 * @brief 上报告警信息
 *
 * @param [in] batValue
 * @param [in] timeStamp
 * @param [in] alarmType
 * @param [in] userId
 *
 * @note
 */
static void FuncNb_lkm3_report_alarm_info_Handle(uint32_t timeStamp, uint8_t alarmType, uint8_t userId)
{
    NB_reportAlarmInfo_cmd_stu_t alarmInfoReport;
    uint8_t keyNum = 0;
    NB_NvEvidence_stu_t evidenceData = {0};

    memset(&alarmInfoReport, 0, sizeof(alarmInfoReport));

    alarmInfoReport.cmd = NB_LKM3_CMD_REPORT_ALARM_INFO;
    alarmInfoReport.batteryLevel = SYS_CALL(Battery_Get);
    alarmInfoReport.openTimeStamp = timeStamp;
    alarmInfoReport.alarmType = FuncNb_lkm3_alarm_type_convert(alarmType);
    alarmInfoReport.EvidenceID = userId;
    keyNum = SYS_CALL(Users_MatchKeysLibrary, USERS_TYPE_EVIDENCE, &userId, sizeof(userId), 1, &evidenceData);
    alarmInfoReport.EvidenceStartTime = evidenceData.stime;
    alarmInfoReport.EvidenceEndTime = evidenceData.etime;

    NbMain_send_data_to_Nblot(0, 0, sizeof(alarmInfoReport), (uint8_t *)&alarmInfoReport);
}

/**
 * @brief 上报开锁记录信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_report_openLock_record_Handle(uint32_t timeStamp, uint8_t userId)
{
    NB_reportOpenLockInfo_cmd_stu_t unlockRecordReport;

    memset(&unlockRecordReport, 0, sizeof(unlockRecordReport));

    unlockRecordReport.cmd = NB_LKM3_CMD_REPORT_OPEN_LOCK_RECORD;
    unlockRecordReport.EvidenceID = userId;
    unlockRecordReport.batteryLevel = SYS_CALL(Battery_Get);
    unlockRecordReport.openLockType = 0x05; // 0x05蓝牙开门
    unlockRecordReport.openTimeStamp = timeStamp;
    unlockRecordReport.openLockInfo = 0x01; // 0x01正常开门， 0x5胁迫开门
    unlockRecordReport.recordId = 0;

    NbMain_send_data_to_Nblot(0, 0, sizeof(unlockRecordReport), (uint8_t *)&unlockRecordReport);
}

/**
 * @brief 按照协议需求，转换NB UE数据
 *
 * @param [in] src 源数据
 * @param [in] srcLen 源数据长度
 * @param [in] des 转化后的数据
 *
 * @note
 */
static void FuncNb_lkm3_report_heartBeat_convert(uint8_t *src, uint8_t srcLen, uint8_t *des)
{
    uint8_t tempStr[10] = {0};
    uint8_t tempHex[10] = {0};
    uint8_t hexLen = 0;
    uint8_t tempStrLen = srcLen;
    uint8_t dataLen = 0; //不算正负号，只算数据的长度

    //上报NB信息
    if (src[0] == '-') //如果是负数，首字节为2D， 如果是正数，首字节为2B
    {
        tempHex[0] = 0x2D;
        dataLen = tempStrLen - 1;

        if (dataLen % 2 != 0) //不算减号，只算数据的长度，转化为HEX必须是2的倍数，不是的话前边补0
        {
            tempStr[0] = '0';
            memcpy(&tempStr[1], &src[1], dataLen);
            hexLen = SYS_CALL(NB_TASK_str_to_hex, tempStr, &tempHex[1], dataLen + 1); //数据的长度 + 补0的长度
        }
        else
        {
            memcpy(&tempStr[0], &src[1], dataLen);
            hexLen = SYS_CALL(NB_TASK_str_to_hex, tempStr, &tempHex[1], dataLen);
        }
    }
    else
    {
        tempHex[0] = 0x2B;
        dataLen = tempStrLen;

        if (dataLen % 2 != 0)
        {
            tempStr[0] = '0';
            memcpy(&tempStr[1], &src[0], dataLen);
            hexLen = SYS_CALL(NB_TASK_str_to_hex, tempStr, &tempHex[1], dataLen + 1); //数据的长度 + 补0的长度
        }
        else
        {
            memcpy(&tempStr[0], &src[0], dataLen);
            hexLen = SYS_CALL(NB_TASK_str_to_hex, tempStr, &tempHex[1], dataLen);
        }
    }

    memcpy(des, tempHex, hexLen);
}

/**
 * @brief 上报心跳信息
 *
 * @param [in] heartBeatType 心跳类型
 *
 * @note
 */
static void FuncNb_lkm3_report_heartBeat_Handle(uint8_t heartBeatType, uint8_t heartBeatPeriod, uint8_t startHeartBeatType)
{
    static uint16_t mid = 0;
    static uint8_t sid = 0;
    uint8_t DestroyStatus = 0;
    NB_reportHeartBeatInfo_cmd_stu_t reportHeart;
    NB_reportNbinfo_stu_t *pNbInfo = (NB_reportNbinfo_stu_t *)reportHeart.NbInfo;

    memset(&reportHeart, 0, sizeof(reportHeart));

    reportHeart.cmd = NB_LKM3_CMD_REPORT_HEARTBEAT_INFO;
    reportHeart.batteryLevel = SYS_CALL(Battery_Get);
    reportHeart.heartBeatType = heartBeatType;
    reportHeart.heartBeatPeriod = heartBeatPeriod;
    reportHeart.startHeartBeat = startHeartBeatType;
    reportHeart.deviceCurStutas = DEVICE_CUR_STATUS_POWER_SAVING;
    reportHeart.deviceRunMode = DEVICE_RUN_STATUS_MANUAL_POWER_SAVING;
    DestroyStatus = (Local_LockGetSysFlag(SYS_FLAG_TAMPER_ALARM) == true) ? 0x02 : 0x01;
    reportHeart.destroyStatus = DestroyStatus; // 0x01 正常， 0x02 异常
    if (reportHeart.heartBeatType == HEART_BEAT_TYPE_TOUCH || reportHeart.heartBeatType == HEART_BEAT_TYPE_RCC_RELEASE)
    {
        memset(reportHeart.NbInfo, 0, sizeof(reportHeart.NbInfo));
    }
    else
    {
        FuncNb_lkm3_report_heartBeat_convert(nbUeParam.cellId, nbUeParam.cellIdLen, pNbInfo->cellId);
        FuncNb_lkm3_report_heartBeat_convert(nbUeParam.dlEarfcn, nbUeParam.dlEarfcnLen, pNbInfo->earfcn);
        FuncNb_lkm3_report_heartBeat_convert(nbUeParam.pci, nbUeParam.pciLen, pNbInfo->pci);
        FuncNb_lkm3_report_heartBeat_convert(nbUeParam.rsrp, nbUeParam.rsrpLen, pNbInfo->signalPower);
        FuncNb_lkm3_report_heartBeat_convert(nbUeParam.snr, nbUeParam.snrLen, pNbInfo->snr);
        FuncNb_lkm3_report_heartBeat_convert(nbUeParam.txPower, nbUeParam.txPowerLen, pNbInfo->txPower);
    }

    NbMain_send_data_to_Nblot(mid++, sid++, sizeof(reportHeart), (uint8_t *)&reportHeart);
}

/**
 * @brief 上报版本信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_report_version_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_reportVersioin_cmd_stu_t pReportVers;
    uint16_t softVersion = FIRMWARE_VERSION;
    uint16_t hardVersion = OSAL_SWAP16(HARDWARE_VERSION);
    uint16_t productID = OSAL_SWAP16(PRODUCE_ID);
    uint8_t iemi[16] = {0};
    uint8_t bleMac[6] = {0};
    uint8_t simIccid[30] = {0};

    memset(&pReportVers, 0, sizeof(pReportVers));

    OSAL_NvRead(SYS_OFFSET(nbIemi), iemi, 15);
    iemi[15] = '0';

    pReportVers.cmd = NB_LKM3_CMD_REPORT_VERSION;
    pReportVers.softVersion = OSAL_SWAP16(softVersion);
    memcpy(pReportVers.hardVersion, &hardVersion, 2);
    memcpy(&pReportVers.hardVersion[2], &productID, 2);
    SYS_CALL(NB_TASK_str_to_hex, iemi, pReportVers.moduleId, sizeof(iemi));
    OSAL_NvRead(SYS_OFFSET(bleMacAddr), bleMac, sizeof(bleMac));
    memcpy(pReportVers.bleModuleId, bleMac, sizeof(bleMac));
    memcpy(&pReportVers.bleModuleId[6], &pReportVers.softVersion, 2);
    pReportVers.netTrigger = JOIN_NETWORK_POWER_ON;

    OSAL_NvRead(SYS_OFFSET(nbIccid), simIccid, 20);
    SYS_CALL(NB_TASK_str_to_hex, simIccid, pReportVers.simIccid, sizeof(simIccid));

    NbMain_send_data_to_Nblot(0, 0, sizeof(pReportVers), (uint8_t *)&pReportVers);
}

/**
 * @brief 查询版本信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_inquiry_version_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_inquiryVersioin_cmd_stu_t *pInquiryVer = (NB_inquiryVersioin_cmd_stu_t *)pdata;
    NB_inquiryVersion_ack_stu_t inquiryVerAck;
    uint8_t bleMac[6] = {0};
    uint8_t iemi[16] = {0};
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;
    uint16_t hardVersion = OSAL_SWAP16(HARDWARE_VERSION);
    uint16_t productID = OSAL_SWAP16(PRODUCE_ID);

    memset(&inquiryVerAck, 0, sizeof(inquiryVerAck));

    // nb_nv_read_test();
    if (NbMain_auth_verify(pInquiryVer->Auth, sizeof(pInquiryVer->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pInquiryVer->failureTime) == SUCCESS)
        {
            OSAL_NvRead(SYS_OFFSET(nbIemi), iemi, 15);
            iemi[15] = '0';
            inquiryVerAck.softVersion = OSAL_SWAP16(FIRMWARE_VERSION);
            memcpy(inquiryVerAck.hardVersion, &hardVersion, 2);
            memcpy(&inquiryVerAck.hardVersion[2], &productID, 2);

            SYS_CALL(NB_TASK_str_to_hex, iemi, inquiryVerAck.moduleId, sizeof(iemi));
            OSAL_NvRead(SYS_OFFSET(bleMacAddr), bleMac, sizeof(bleMac));
            memcpy(inquiryVerAck.bleModuleId, bleMac, sizeof(bleMac));
            memcpy(&inquiryVerAck.bleModuleId[6], &inquiryVerAck.softVersion, 2);

            result = EVIDENCE_ACK_SUCCESS;
        }
    }

    inquiryVerAck.ackCmd = pInquiryVer->cmd;
    inquiryVerAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(inquiryVerAck), (uint8_t *)&inquiryVerAck);
    SYS_CALL(FuncBle_lkm3_version_Handle, result, inquiryVerAck.softVersion, inquiryVerAck.hardVersion, inquiryVerAck.moduleId, inquiryVerAck.bleModuleId);
}

/**
 * @brief 设置心跳上报周期
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_heartBeat_period_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_setHeartBeatPeriod_cmd_stu_t *pSetHeartBeatPeriod = (NB_setHeartBeatPeriod_cmd_stu_t *)pdata;
    NB_setHeartBeatPeriod_ack_stu_t setHeartBeatPeriodAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&setHeartBeatPeriodAck, 0, sizeof(setHeartBeatPeriodAck));

    if (NbMain_auth_verify(pSetHeartBeatPeriod->Auth, sizeof(pSetHeartBeatPeriod->Auth)) == SUCCESS)
    {
        FUNC_NB_LOG_D("Set heartBeat:%d", pSetHeartBeatPeriod->period);
        uint16_t HeartBeat[HEARTBEAT_MAX_TIMES] = {1, 2, 3, 12, 24, 48, 288};
        uint32_t cycle = (24 * 3600) / HeartBeat[pSetHeartBeatPeriod->period];
        RtcAlarm_Set(HEART_BEAT_NAME, cycle, SET);
        OSAL_NvWrite(SYS_OFFSET(heartBeatReportPeriod), &pSetHeartBeatPeriod->period, 1);
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    setHeartBeatPeriodAck.ackCmd = pSetHeartBeatPeriod->cmd;
    setHeartBeatPeriodAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(setHeartBeatPeriodAck), (uint8_t *)&setHeartBeatPeriodAck);

    SYS_CALL(FuncBle_lkm3_heardBeatSet_Handle, result, pSetHeartBeatPeriod->period);
}

/**
 * @brief 设置云平台南向地址
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_south_address_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_setSouthAddr_cmd_stu_t *pSouthAddr = (NB_setSouthAddr_cmd_stu_t *)pdata;
    FUNC_NB_LOG_D("setSouthAddr:%s  port:%s", &pSouthAddr->southIpAddr, &pSouthAddr->port);
    OSAL_NvWrite(SYS_OFFSET(nbSouthIpAddr), &pSouthAddr->southIpAddr, 16);
    OSAL_NvWrite(SYS_OFFSET(nbport), &pSouthAddr->port, 4);
}

/**
 * @brief 设置音量
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_volume_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_setVolume_cmd_stu_t *pSetVol = (NB_setVolume_cmd_stu_t *)pdata;
    NB_setVolume_ack_stu_t setVolAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&setVolAck, 0, sizeof(setVolAck));

    if (NbMain_auth_verify(pSetVol->Auth, sizeof(pSetVol->Auth)) == SUCCESS)
    {
        FUNC_NB_LOG_D("Set volume:%d", pSetVol->volume);
        switch (pSetVol->volume)
        {
        case SET_VOLUME_HIGH:
        {
        }
        break;

        case SET_VOLUME_MIDDLE:
        {
        }
        break;

        case SET_VOLUME_LOW:
        {
        }
        break;

        default:
            break;
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    setVolAck.ackCmd = pSetVol->cmd;
    setVolAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(setVolAck), (uint8_t *)&setVolAck);

    // SYS_CALL(FuncBle_lkm3_general_ack_Handle, 0x7ABA09, result);//TODO:蓝牙协议中没有这条
}

/**
 * @brief 设置时间
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_time_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_setTime_cmd_stu_t *pSetTime = (NB_setTime_cmd_stu_t *)pdata;
    NB_setTime_ack_stu_t setTimeAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;
    uint32_t serverTimeStamps = 0;

    memset(&setTimeAck, 0, sizeof(setTimeAck));

    if (NbMain_auth_verify(pSetTime->Auth, sizeof(pSetTime->Auth)) == SUCCESS)
    {
        serverTimeStamps = OSAL_SWAP32(pSetTime->timeStamps);
        FUNC_NB_LOG_D("Set time:%d, 0x%x", serverTimeStamps, serverTimeStamps);
        OSAL_TimeSet(&serverTimeStamps, T_UTC);
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    setTimeAck.ackCmd = pSetTime->cmd;
    setTimeAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(setTimeAck), (uint8_t *)&setTimeAck);

    SYS_CALL(FuncBle_lkm3_timeSet_Handle, result, serverTimeStamps);
}

/**
 * @brief 重启设备
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_restart_device_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_restartDevice_cmd_stu_t *pRstDevice = (NB_restartDevice_cmd_stu_t *)pdata;
    NB_restartDevice_ack_stu_t rstDeviceAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&rstDeviceAck, 0, sizeof(rstDeviceAck));

    FUNC_NB_LOG_D("operationType:%d", pRstDevice->operationType);
    if (NbMain_auth_verify(pRstDevice->Auth, sizeof(pRstDevice->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pRstDevice->failureTime) == SUCCESS)
        {
            if (pRstDevice->operationType == 0x01) //软重启
            {
                //重启设备
                FUNC_NB_LOG_W("restart device  time Later:%d", 2000);
                OSAL_SystemReset(3000);
                SYS_CALL(Set_SilentRest_flag, SET); //静默复位
            }
        }
    }

    FUNC_NB_LOG_D("result:%d", result);
    rstDeviceAck.ackCmd = pRstDevice->cmd;
    rstDeviceAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(rstDeviceAck), (uint8_t *)&rstDeviceAck);

    SYS_CALL(FuncBle_lkm3_general_ack_Handle, 0xBA09, result);
}
/**
 * @brief 清空门锁上存储的所有凭证信息或者凭证日志
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_reset_factory_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_resetFactore_cmd_stu_t *pRstFactory = (NB_resetFactore_cmd_stu_t *)pdata;
    NB_resetFactore_ack_stu_t resetFactoryAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&resetFactoryAck, 0, sizeof(resetFactoryAck));

    FUNC_NB_LOG_D("operationType:%d", pRstFactory->operationType);
    if (NbMain_auth_verify(pRstFactory->Auth, sizeof(pRstFactory->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pRstFactory->failureTime) == SUCCESS)
        {
            if (pRstFactory->operationType = 0x01)
            {
                SYS_CALL(FuncBle_lkm3_general_ack_Handle, 0xBA08, result);
                //恢复出厂设置
                FUNC_NB_LOG_W("Reset factory");
                Local_NvReset(2);                   //不要重启
            }
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    resetFactoryAck.ackCmd = pRstFactory->cmd;
    resetFactoryAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(resetFactoryAck), (uint8_t *)&resetFactoryAck);
}

/**
 * @brief 清空门锁上存储的所有凭证信息或者凭证日志
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_reset_data_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_resetEvidenceInfo_cmd_stu_t *pResetData = (NB_resetEvidenceInfo_cmd_stu_t *)pdata;
    NB_resetEvidenceInfo_ack_stu_t resetDataAck;
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;

    memset(&resetDataAck, 0, sizeof(resetDataAck));

    FUNC_NB_LOG_D("operationType:%d", pResetData->operationType);

    if (NbMain_auth_verify(pResetData->Auth, sizeof(pResetData->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pResetData->failureTime) == SUCCESS)
        {
            if (pResetData->operationType == CLEAR_EVIDENCE_INFO)
            {
                //清空凭证信息
                result = NBMain_delete_evidence(DEL_ALL_EVIDENCE, 0);
            }
            else if (pResetData->operationType == CLEAR_EVIDENCE_LOG)
            {
                //清空凭证操作日志
            }
        }
        else
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    FUNC_NB_LOG_D("result:%d", result);
    resetDataAck.ackCmd = pResetData->cmd;
    resetDataAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(resetDataAck), (uint8_t *)&resetDataAck);

    SYS_CALL(FuncBle_lkm3_general_ack_Handle, 0xBA07, result);
}

/**
 * @brief 更新凭证状态
 *
 * @param [in] evidenceId
 * @param [in] operationType
 * @return uint8_t
 *
 * @note
 */
static uint8_t NBMain_update_evidence(uint8_t evidenceId, uint8_t operationType, uint8_t evidenceStatus)
{
    uint8_t updataId = 0;
    uint8_t updataType = 0;
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;

    if (operationType == UPDATE_SINGLE_EVIDENCE)
    {
        updataId = evidenceId;
        updataType = 0;
    }
    else if (operationType == UPDATE_ALL_EVIDENCE)
    {
        updataId = 0;
        updataType = 0xff;
    }
    if (SYS_CALL(Users_updata_keys_status, USERS_TYPE_EVIDENCE, updataId, evidenceStatus, updataType) == SUCCESS)
    {
        result = EVIDENCE_ACK_SUCCESS;
    }
    FUNC_NB_LOG_D("updataId:%d, updataType:%d, result:%d, evidenceStatus:%d", updataId, updataType, result, evidenceStatus);
    return result;
}
/**
 * @brief 更新凭证信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_update_evidence_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_updateEvidence_cmd_stu_t *pUpdateEvid = (NB_updateEvidence_cmd_stu_t *)pdata;
    NB_updateEvidence_ack_stu_t updateEvidAck;
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;

    memset(&updateEvidAck, 0, sizeof(updateEvidAck));

    FUNC_NB_LOG_D("Updata evidence evidenceID:%d", pUpdateEvid->evidenceID);
    FUNC_NB_LOG_D("Updata evidence operationType:%d", pUpdateEvid->operationType);

    if (NbMain_auth_verify(pUpdateEvid->Auth, sizeof(pUpdateEvid->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pUpdateEvid->failureTime) == SUCCESS)
        {
            result = NBMain_update_evidence(pUpdateEvid->evidenceID, pUpdateEvid->operationType, pUpdateEvid->evidenceStusus);
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    updateEvidAck.ackCmd = pUpdateEvid->cmd;
    updateEvidAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(updateEvidAck), (uint8_t *)&updateEvidAck);

    SYS_CALL(FuncBle_lkm3_updateEvidence_Handle, result, pUpdateEvid->operationType, pUpdateEvid->evidenceID, pUpdateEvid->evidenceStusus);
}

/**
 * @brief 修改凭证生效时间
 *
 * @param [in] evidenceId
 * @param [in] startTime
 * @param [in] endTime
 * @return uint8_t
 *
 * @note
 */
static uint8_t NBMain_modify_evidence(uint8_t evidenceId, uint32_t startTime, uint32_t endTime)
{
    UserAttrPloy_stu_t attr_ploy;
    uint8_t result = EVIDENCE_ACK_SUCCESS;
    uint8_t keyNum = 0;
    uint8_t ret = 0;
    NB_NvEvidence_stu_t evidenceData = {0};

    keyNum = SYS_CALL(Users_MatchKeysLibrary, USERS_TYPE_EVIDENCE, &evidenceId, sizeof(evidenceId), 1, &evidenceData);

    FUNC_NB_LOG_D("modify keyNum: %d, evidenceId:%d, readId:%d", keyNum, evidenceId, evidenceData.EvidenceId);
    FUNC_NB_LOG_D("modify EvidenceStatus:0x%d", evidenceData.EvidenceStatus);
    FUNC_NB_LOG_D("modify startTimeStamp:0x%x, %d", evidenceData.stime, evidenceData.stime);
    FUNC_NB_LOG_D("modify endTimeStamp:0x%x, %d", evidenceData.etime, evidenceData.etime);
    FUNC_NB_LOG_HEX("modify value:", evidenceData.Evidence, sizeof(evidenceData.Evidence));

    if (keyNum != 0xff)
    {
        memset(&attr_ploy, 0, sizeof(UserAttrPloy_stu_t));
        attr_ploy.attr = USERS_ATTR_PLOY;
        attr_ploy.ploy.week = 0;
        attr_ploy.ploy.stime = OSAL_SWAP32(startTime);
        attr_ploy.ploy.etime = OSAL_SWAP32(endTime);
        ret = SYS_CALL(Users_SetAttrPloy, USERS_TYPE_EVIDENCE, keyNum, attr_ploy.attr, &attr_ploy.ploy);
        FUNC_NB_LOG_D("ret:, %d", ret);
        if (ret == SUCCESS)
        {
            result = EVIDENCE_ACK_SUCCESS;
        }
    }
    else
    {
        result = EVIDENCE_ACK_ID_NOT_EXIST;
    }
    return result;
}

/**
 * @brief 修改凭证信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_modify_evidence_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_modifyEvidence_cmd_stu_t *pModifyEvi = (NB_modifyEvidence_cmd_stu_t *)pdata;
    NB_modifyEvidence_ack_stu_t ModifyEviAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&ModifyEviAck, 0, sizeof(ModifyEviAck));

    FUNC_NB_LOG_D("Modify_evidence evidenceID:%d", pModifyEvi->evidenceID);

    if (NbMain_auth_verify(pModifyEvi->Auth, sizeof(pModifyEvi->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pModifyEvi->failureTime) == SUCCESS)
        {
            result = NBMain_modify_evidence(pModifyEvi->evidenceID, pModifyEvi->startTimeStamp, pModifyEvi->endTimeStamp);
        }
        else
        {
            result = EVIDENCE_ACK_DATE_ERROR;
        }
    }
    else
    {
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    ModifyEviAck.ackCmd = pModifyEvi->cmd;
    ModifyEviAck.result = result;
    NbMain_send_data_to_Nblot(mid, sid, sizeof(ModifyEviAck), (uint8_t *)&ModifyEviAck);

    SYS_CALL(FuncBle_lkm3_modifyEvidence_Handle, result, pModifyEvi->evidenceID, pModifyEvi->startTimeStamp, pModifyEvi->endTimeStamp);
}

/**
 * @brief 开门上报结果类型转换
 *
 * @param [in] localType
 * @return uint8_t
 *
 * @note
 */  
static uint8_t FuncNb_lkm3_network_openLock_ack_convert(uint8_t localType)
{
    uint8_t nbType = 0;

    switch (localType)
    {
    case USERS_ID_SYSLOCK: //凭证试开
        nbType = EVIDENCE_ACK_ERROR;
        break;

    case USERS_ID_RFEEZE: //冻结状态
        nbType = EVIDENCE_ACK_FREEZE;
        break;

    default:
        nbType = localType;
        break;
    }

    return nbType;
}

/**
 * @brief 网络开门指令
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_network_openLock_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_netOpenLock_cmd_stu_t *pNetOpenLock = (NB_netOpenLock_cmd_stu_t *)pdata;
    NB_netOpenLock_ack_stu_t netOpenLockAck;
    uint8_t result = EVIDENCE_ACK_AUTH_ERROR;
    uint8_t time = Menu_GetSystemLockedStatus();

    memset(&netOpenLockAck, 0, sizeof(netOpenLockAck));

    FUNC_NB_LOG_D("NetOpenLock cmd:%d", pNetOpenLock->cmd);
    FUNC_NB_LOG_D("NetOpenLock failureTime:%d, 0X%x", OSAL_SWAP32(pNetOpenLock->failureTime), pNetOpenLock->failureTime);
    FUNC_NB_LOG_D("NetOpenLock evidenceID:%d", pNetOpenLock->evidenceID);
    FUNC_NB_LOG_D("NetOpenLock serverTimeStamp:%d", OSAL_SWAP32(pNetOpenLock->serverTimeStamp));
    FUNC_NB_LOG_HEX("NetOpenLock Auth:", pNetOpenLock->Auth, sizeof(pNetOpenLock->Auth));
    FUNC_NB_LOG_HEX("NetOpenLock evidenceValue:", pNetOpenLock->evidenceValue, sizeof(pNetOpenLock->evidenceValue));

    if (NbMain_auth_verify(pNetOpenLock->Auth, sizeof(pNetOpenLock->Auth)) == SUCCESS)
    {
        if (NbMain_time_verify(pNetOpenLock->failureTime) == SUCCESS)
        {
                result = SYS_CALL(Users_Verify, pNetOpenLock->evidenceValue, sizeof(pNetOpenLock->evidenceValue), RESET, USERS_TYPE_EVIDENCE, 1, 0);
                if ((result == EVIDENCE_ACK_SUCCESS) && (time == 0))
                {
                    FUNC_NB_LOG_D("Active status, evidence Verify success, open lock");
                    SYS_CALL(Local_LockControl, USERS_TYPE_EVIDENCE, pNetOpenLock->evidenceID, LOCK_CTRL_UNLOCK);
                }
                else
                {
                    if (time > 0)
                    {
                        result = USERS_ID_SYSLOCK;
                        Led_Set("LED_LOGO_R", LED_FLASH, 3, 300);
                        Local_LockSaveRecord(EVENT_TYPE_ALARM, USERS_TYPE_EVIDENCE, EVENT_CODE_SYSLOCK, 0X00); //上报试开凭证
                        FUNC_NB_LOG_D("FuncNb_lkm3_network_openLock_Handle, evidence Verify error:%d", result);
                    }
                    else
                    {
                        Menu_ProcessVerifyFailed();
                        time = Menu_GetSystemLockedStatus();
                        if (time > 0)
                        {
                            result = USERS_ID_SYSLOCK;
                            Led_Set("LED_LOGO_R", LED_FLASH, 3, 300);
                            Local_LockSaveRecord(EVENT_TYPE_ALARM, USERS_TYPE_EVIDENCE, EVENT_CODE_SYSLOCK, 0X00); //上报试开凭证
                            FUNC_NB_LOG_D("FuncNb_lkm3_network_openLock_Handle 02, evidence Verify error:%d", result);
                        }
                        else
                        {
                            Led_Set("LED_LOGO_R", LED_FLASH, 1, 2000);
                            FUNC_NB_LOG_D("evidence Verify error:%d", result);
                        }
                    }
                }
        }
    }
    else
    {
        Led_Set("LED_LOGO_R", LED_FLASH, 1, 2000);
        result = EVIDENCE_ACK_AUTH_ERROR;
    }

    netOpenLockAck.result = FuncNb_lkm3_network_openLock_ack_convert(result);
    netOpenLockAck.ackCmd = pNetOpenLock->cmd;
    netOpenLockAck.evidenceID = pNetOpenLock->evidenceID;
    netOpenLockAck.batteryLevel = SYS_CALL(Battery_Get);
    netOpenLockAck.openLockType = 0x05;
    netOpenLockAck.openLockTimeStamp = pNetOpenLock->failureTime + 5;
    netOpenLockAck.recordId = OSAL_SWAP16(0X0001);

    NbMain_send_data_to_Nblot(mid, sid, sizeof(netOpenLockAck), (uint8_t *)&netOpenLockAck);

    if (result != EVIDENCE_ACK_SUCCESS)
    {
        SYS_CALL(FuncBle_lkm3_unLockSta_Handle, result, pNetOpenLock->evidenceID, pNetOpenLock->failureTime + 5);
    }
}

/**
 * @brief 删除已存储的凭证
 *
 * @param [in] delType
 * @param [in] delEvidId
 * @return uint8_t
 *
 * @note
 */
static uint8_t NBMain_delete_evidence(uint8_t delType, uint8_t delEvidId)
{
    uint8_t result = EVIDENCE_ACK_ERROR;

    if (DEL_SINGLE_EVIDENCE == delType)
    {
        if (SYS_CALL(Users_Del, USERS_TYPE_EVIDENCE, 0xFF, &delEvidId, sizeof(delEvidId)) >= 0)
        {
            result = EVIDENCE_ACK_SUCCESS;
        }
    }
    else if (DEL_ALL_EVIDENCE == delType)
    {
        if (SYS_CALL(Users_Del, USERS_TYPE_EVIDENCE, 0xFF, NULL, 0) >= 0)
        {
            result = EVIDENCE_ACK_SUCCESS;
        }
    }

    return result;
}

/**
 * @brief 删除凭证信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_del_evidence_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_delEvidence_cmd_stu_t *pDelEvid = (NB_addEvidence_cmd_stu_t *)pdata;
    NB_delEvidence_ack_stu_t delEvidAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&delEvidAck, 0, sizeof(delEvidAck));

    FUNC_NB_LOG_D("del ID:%d", pDelEvid->delEvidenceID);
    FUNC_NB_LOG_D("del operation type:%d", pDelEvid->operationType);
    FUNC_NB_LOG_D("del failureTime:0x%x, %d", pDelEvid->failureTime, OSAL_SWAP32(pDelEvid->failureTime));
    FUNC_NB_LOG_HEX("LOT Del evid value:", pDelEvid->Auth, sizeof(pDelEvid->Auth));

    if (SYS_CALL(BleMain_get_activeStatus) == SET)
    {
        if (NbMain_auth_verify(pDelEvid->Auth, sizeof(pDelEvid->Auth)) == SUCCESS)
        {
            result = NBMain_delete_evidence(pDelEvid->operationType, pDelEvid->delEvidenceID);
        }
        else
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
        }

        delEvidAck.ackCmd = pDelEvid->cmd;
        delEvidAck.result = result;
        NbMain_send_data_to_Nblot(mid, sid, sizeof(delEvidAck), (uint8_t *)&delEvidAck);
    }
    else //非激活时，需要校验时间，因为时间在激活之后才能校准
    {
        if (NbMain_auth_verify(pDelEvid->Auth, sizeof(pDelEvid->Auth)) == SUCCESS)
        {
            if (NbMain_time_verify(pDelEvid->failureTime) == SUCCESS)
            {
                result = NBMain_delete_evidence(pDelEvid->operationType, pDelEvid->delEvidenceID);
            }
            else
            {
                result = EVIDENCE_ACK_ERROR;
            }
        }
        else
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
        }

        delEvidAck.ackCmd = pDelEvid->cmd;
        delEvidAck.result = result;
        NbMain_send_data_to_Nblot(mid, sid, sizeof(delEvidAck), (uint8_t *)&delEvidAck);

        SYS_CALL(FuncBle_lkm3_delEvidence_Handle, result, pDelEvid->operationType, pDelEvid->delEvidenceID);
    }
}

/**
 * @brief NB添加凭证操作
 *
 * @param [in] evidenceId
 * @param [in] evidenceValue
 * @param [in] evidenceLen
 * @param [in] startTime
 * @param [in] endTime
 * @return uint8_t
 *
 * @note
 */
static uint8_t NBMain_add_evidence(uint8_t evidenceId, uint8_t *evidValue, uint8_t evidenceLen, uint32_t startTime, uint32_t endTime)
{
    UsersAddRes_enum_t res = ADD_ERROR;
    UserAttrPloy_stu_t attr_ploy;
    uint8_t ret = ERROR;
    uint8_t result = EVIDENCE_ACK_ERROR;
    uint8_t Num = SYS_CALL(Users_GetValidId, USERS_TYPE_EVIDENCE); //密钥编号和凭证ID不挂钩，锁端单独管理，从0开始编号
    uint8_t evidenceValue[9] = {0};                                // 元素0表示凭证ID， 其余8个字节为凭证

    FUNC_NB_LOG_D("add ID:%d, keyNum:%d", evidenceId, Num);
    FUNC_NB_LOG_D("add startTimeStamp:0x%x, %d", OSAL_SWAP32(startTime), OSAL_SWAP32(startTime));
    FUNC_NB_LOG_D("add endTimeStamp:0x%x, %d", OSAL_SWAP32(endTime), OSAL_SWAP32(endTime));
    FUNC_NB_LOG_HEX("LOT set evid value:", evidValue, evidenceLen);

    evidenceValue[0] = evidenceId;
    memcpy(&evidenceValue[1], evidValue, evidenceLen);

    res = SYS_CALL(Users_Add, USERS_TYPE_EVIDENCE, Num, evidenceValue, evidenceLen, USERS_ATTR_PLOY, RESET);

    FUNC_NB_LOG_D("add res :%d\r\n", res);
    switch (res)
    {
    case ADD_SUCCESS: //添加成功
        memset(&attr_ploy, 0, sizeof(UserAttrPloy_stu_t));
        attr_ploy.attr = USERS_ATTR_PLOY;
        attr_ploy.ploy.week = 0;
        attr_ploy.ploy.stime = OSAL_SWAP32(startTime);
        attr_ploy.ploy.etime = OSAL_SWAP32(endTime);
        ret = SYS_CALL(Users_SetAttrPloy, USERS_TYPE_EVIDENCE, Num, attr_ploy.attr, &attr_ploy.ploy);
        if (ret == SUCCESS)
        {
            result = EVIDENCE_ACK_SUCCESS;
        }
        break;

    case ADD_ERR_EXISTS: //密码已存在
        result = EVIDENCE_ACK_ID_EXIST;
        break;

    case ADD_ERR_KEYS_LIB_IS_FULL: //凭证库已满
        result = EVIDENCE_ACK_FULL;
        break;

    case ADD_ERROR: //添加失败
        result = EVIDENCE_ACK_ERROR;
        break;
    default:
        break;
    }
    return result;
}

/**
 * @brief 添加凭证信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_add_evidence_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_addEvidence_cmd_stu_t *pAddEvid = (NB_addEvidence_cmd_stu_t *)pdata;
    NB_addEvidence_ack_stu_t addEvidAck;
    uint8_t result = EVIDENCE_ACK_SUCCESS;

    memset(&addEvidAck, 0, sizeof(addEvidAck));

    FUNC_NB_LOG_D("activeStatus:%d", SYS_CALL(BleMain_get_activeStatus));
    if (SYS_CALL(BleMain_get_activeStatus) == SET)
    {
        if (NbMain_auth_verify(pAddEvid->Auth, sizeof(pAddEvid->Auth)) == SUCCESS)
        {
            result = NBMain_add_evidence(pAddEvid->addEvidenceID, pAddEvid->evidenceValue, sizeof(pAddEvid->evidenceValue), pAddEvid->startTimeStamp, pAddEvid->endTimeStamp);
        }
        else
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
        }
        addEvidAck.ackCmd = pAddEvid->cmd;
        addEvidAck.result = result;
        NbMain_send_data_to_Nblot(mid, sid, sizeof(addEvidAck), (uint8_t *)&addEvidAck);
        if (nbSendResTimer == NULL)
        {
            nbSendResTimer = OSAL_TimerCreate(NB_sendResultCallback, 1000, RESET);
        }
    }
    else //非激活时，需要校验时间，因为时间在激活之后才能校准
    {
        if (NbMain_auth_verify(pAddEvid->Auth, sizeof(pAddEvid->Auth)) == SUCCESS)
        {
            if (NbMain_time_verify(pAddEvid->failureTime) == SUCCESS)
            {
                result = NBMain_add_evidence(pAddEvid->addEvidenceID, pAddEvid->evidenceValue, sizeof(pAddEvid->evidenceValue), pAddEvid->startTimeStamp, pAddEvid->endTimeStamp);
            }
            else
            {
                result = EVIDENCE_ACK_DATE_ERROR;
            }
        }
        else
        {
            result = EVIDENCE_ACK_AUTH_ERROR;
        }
        addEvidAck.ackCmd = pAddEvid->cmd;
        addEvidAck.result = result;
        NbMain_send_data_to_Nblot(mid, sid, sizeof(addEvidAck), (uint8_t *)&addEvidAck);
        SYS_CALL(FuncBle_lkm3_addEvidence_Handle, result, pAddEvid->addEvidenceID, pAddEvid->startTimeStamp, pAddEvid->endTimeStamp);
    }
}

/**
 * @brief 设置指令鉴权信息
 *
 * @param [in] mid
 * @param [in] sid
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_authentication_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_Set_Auth_cmd_stu_t *pSetAuth = (NB_Set_Auth_cmd_stu_t *)pdata;
    NB_Set_Auth_ack_stu_t setAuthAck;

    memset(&setAuthAck, 0, sizeof(setAuthAck));

    FUNC_NB_LOG_D("failureTime:0x%x, %d", OSAL_SWAP32(pSetAuth->failureTime), OSAL_SWAP32(pSetAuth->failureTime));
    FUNC_NB_LOG_HEX("LOT set auth:", pSetAuth->Auth, sizeof(pSetAuth->Auth));

    setAuthAck.ackCmd = pSetAuth->cmd;
    if (SYS_CALL(BleMain_get_activeStatus) == RESET) //非激活时，需要校验时间，因为时间在激活之后才能校准
    {
        if (NbMain_time_verify(pSetAuth->failureTime) == SUCCESS)
        {
            OSAL_NvWrite(SYS_OFFSET(nbAuthenticationCode), pSetAuth->Auth, sizeof(pSetAuth->Auth));
            setAuthAck.result = NB_LKM3_RESULT_SUCCESS;
        }
        else
        {
            setAuthAck.result = NB_LKM3_RESULT_PARAM_ERROR;
        }
    }
    else
    {
        OSAL_NvWrite(SYS_OFFSET(nbAuthenticationCode), pSetAuth->Auth, sizeof(pSetAuth->Auth));
        setAuthAck.result = NB_LKM3_RESULT_SUCCESS;
    }
    NbMain_send_data_to_Nblot(mid, sid, sizeof(setAuthAck), (uint8_t *)&setAuthAck);
}

/**
 * @brief 设置门锁密钥
 *
 * @param [in] pdata
 * @param [in] dataLen
 *
 * @note
 */
static void FuncNb_lkm3_set_aesKey_Handle(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    NB_Set_key_cmd_stu_t *pSetAesKey = (NB_Set_key_cmd_stu_t *)&pdata[1];
    NB_Set_key_ack_stu_t setAesKeyAck;

    memset(&setAesKeyAck, 0, sizeof(setAesKeyAck));

    FUNC_NB_LOG_D("failureTime:0x%x, %d", OSAL_SWAP32(pSetAesKey->failureTime), OSAL_SWAP32(pSetAesKey->failureTime));
    FUNC_NB_LOG_HEX("LOT send AES key:", pSetAesKey->key, 16);

    setAesKeyAck.ackCmd = pdata[0];
    if (SYS_CALL(BleMain_get_activeStatus) == RESET) //非激活时，需要校验时间，因为时间在激活之后才能校准
    {
        if (NbMain_time_verify(pSetAesKey->failureTime) == SUCCESS)
        {
            setAesKeyAck.result = NB_LKM3_RESULT_SUCCESS;
            Nb_SendAESToNb(pSetAesKey->key, sizeof(pSetAesKey->key));
        }
        else
        {
            setAesKeyAck.result = NB_LKM3_RESULT_PARAM_ERROR;
        }
    }
    else
    {
        setAesKeyAck.result = NB_LKM3_RESULT_SUCCESS;
        Nb_SendAESToNb(pSetAesKey->key, sizeof(pSetAesKey->key));
    }
    NbMain_send_data_to_Nblot(mid, sid, sizeof(setAesKeyAck), (uint8_t *)&setAesKeyAck);
}

/**
 * @brief NB 接收云平台数据处理
 *
 * @param [in] mid 云平台唯一标识，回ACK时回复相同的mid
 * @param [in] sid 唯一标识, 回ACK时回复相同的sid
 * @param [in] pdata CMD+DATA
 * @param [in] dataLen CMD+DATA的长度
 *
 * @note
 */
static void NbMain_ReceiveNbCmd(uint16_t mid, uint8_t sid, uint8_t *pdata, uint16_t dataLen)
{
    uint8_t cmd = pdata[0];

    switch (cmd)
    {
    case NB_LKM3_CMD_SET_AES_KEY: //设置门锁密钥
    {
        FuncNb_lkm3_set_aesKey_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_SET_AUTHENTICATION: //设置配置信息
    {
        FuncNb_lkm3_set_authentication_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_ADD_EVIDENCE: //添加凭证信息
    {
        FuncNb_lkm3_add_evidence_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_DEL_EVIDENCE: //删除凭证信息
    {
        FuncNb_lkm3_del_evidence_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_NET_OPEN_LOCK: //网络开门
    {
        FuncNb_lkm3_network_openLock_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_MODIFY_EVIDENCE: //修改凭证信息
    {
        FuncNb_lkm3_modify_evidence_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_UPDATE_EVIDENCE: //更新凭证信息
    {
        FuncNb_lkm3_update_evidence_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_RESET_DATA: //清空门锁上存储的所有凭证信息或者凭证日志
    {
        FuncNb_lkm3_reset_data_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_RESET_FACTORY: //恢复出厂设置
    {
        FuncNb_lkm3_reset_factory_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_RESET_DEVICE: //门锁系统重启
    {
        FuncNb_lkm3_restart_device_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_SET_TIME: //设置时间
    {
        FuncNb_lkm3_set_time_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_SET_VOLUME: //设置音量
    {
        FuncNb_lkm3_set_volume_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_SET_SOUTH_ADDRESS: //设置云平台南向地址
    {
        FuncNb_lkm3_set_south_address_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_SET_HEART_BRET_PERIOD: //设置心跳上报周期
    {
        FuncNb_lkm3_set_heartBeat_period_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_INQUIRY_VERSION_INFO: //查询版本信息
    {
        FuncNb_lkm3_inquiry_version_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_REPORT_VERSION: //上报版本信息
    {
        FuncNb_lkm3_report_version_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_REPORT_HEARTBEAT_INFO: //上报心跳信息
    {
        // FuncNb_lkm3_report_heartBeat_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_REPORT_OPEN_LOCK_RECORD: //上报开锁记录信息
    {
        // FuncNb_lkm3_report_openLock_record_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_REPORT_ALARM_INFO: //上报告警信息
    {
        // FuncNb_lkm3_report_alarm_info_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_REPORT_RESET_FACTORY: //上报恢复出厂设置
    {
        // FuncNb_lkm3_report_reset_factory_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_SET_FREQUENCY_OF_RESTART: //设置重启频次
    {
        FuncNb_lkm3_set_restart_frequency_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_INQUIRY_CONFIG_INFO: //查询配置信息
    {
        FuncNb_lkm3_inquiry_config_info_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_INQUIRY_EVIDENCE_LIST: //查询凭证列表
    {
        FuncNb_lkm3_inquiry_evidence_list_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_INSTALL_LOCK_INFO: //安装门锁初始化
    {
        FuncNb_lkm3_install_lock_info_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_CMD_INSTALL_LOCK_COMPLETE: //安装门锁完成
    {
        FuncNb_lkm3_install_lock_complete_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_OTA_CMD_UPDATE_REQUEST: // 升级请求
    {
        FUNC_NB_LOG_I("NB OTA request");
        FuncNb_lkm3_ota_request_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_OTA_CMD_FILE_TRANSMIT: // 传输文件分包片
    {
        FuncNb_lkm3_ota_file_Handle(mid, sid, pdata, dataLen);
    }
    break;

    case NB_LKM3_OTA_CMD_FILE_TRANSMIT_END: // 传输结束确认
    {
        FuncNb_lkm3_ota_transmit_Handle(mid, sid, pdata, dataLen);
    }
    break;

    default:
        break;
    }
}

static uint8_t awaitUpdVer[16];
static uint16_t awaitUpdPackSize = 0; //每包大小
static uint16_t awaitUpdPackNums = 0; //总包数
static uint16_t UpdNextPackNum = 0;   //下一包编号
static uint16_t UpdLastPackNum = 0;   //当前包编号，用于重发
static uint32_t AepOta_WtOffSet = 0;  //固件烧录地址
static TimerHandle_stu_t TimerHandle_AepOtaReqUpd = NULL;
static TimerHandle_stu_t TimerHandle_QueryNbConnectSta = NULL;
static TimerHandle_stu_t TimerHandle_ClearAepOtaMark = NULL;
static AepOta_NewVerBackups_stu_t sBackup = {0};

static void AepOta_NvWrite(void)
{
    OSAL_NvWrite(SYS_OFFSET(aepOtaInfor), &sBackup, sizeof(sBackup));
}

static void AepOta_NvRead(void)
{
    OSAL_NvRead(SYS_OFFSET(aepOtaInfor), &sBackup, sizeof(sBackup));
}

/**
 * @brief 通用应答
 * @param [in] cmd
 * @param [in] sta
 * @note
 */
static void AepOta_generalAck_handle(uint8_t cmd, uint8_t sta)
{
    NbMain_send_AepOtaData_to_NbIot(cmd, sizeof(sta), &sta);
}

static void AepOta_stop(void)
{
    FUNC_NB_LOG_D("AepOta stop");
    NBMain_control_nb_psm_status(NB_CONTROL_ENTER_PSM);
}

/**
 * @brief 首次或重新请求个该升级包
 *
 * @note
 */
static void AepOta_ReqUpd_OnePack(void)
{
    AepOta_ReqUpd_stu_t ReqUpd;
    memcpy(ReqUpd.ver, awaitUpdVer, 16);
    ReqUpd.PackNum = OSAL_SWAP16(UpdNextPackNum);
    NbMain_send_AepOtaData_to_NbIot(AEP_OTA_REQ_UPD, sizeof(ReqUpd), &ReqUpd);
}
/**
 * @brief 请求数据超时回调函数
 *
 * @param [in] xTimer
 *
 * @note
 */
static void AepOta_ReqUpd_TimeOut_Callback(TimerHandle_stu_t xTimer)
{
    static uint8_t cnt = 0;
    if (UpdLastPackNum == UpdNextPackNum)
    {
        cnt++;
        if (cnt > AEP_OTA_REQ_ONEPACK_MAX_TIME) //同一包数据请求最大次数,超过则暂停升级，让NB 模组休眠
        {
            cnt = 0;
            OSAL_TimerDelete(TimerHandle_AepOtaReqUpd);
            SYS_CALL(NB_TASK_Set_AepOtaMark, RESET);
            FUNC_NB_LOG_E("AepOta_ReqUpd_TimeOut");
            sBackup.errCnt++;
            if (sBackup.errCnt >= 5)
            {
                sBackup.errCnt = 0;
                sBackup.status = AEP_OTA_STA_NONE;
            }
            AepOta_NvWrite();
            AepOta_stop();
            return;
        }
        AepOta_ReqUpd_OnePack();
    }
    else
    {
        cnt = 0;
        UpdLastPackNum = UpdNextPackNum;
    }
}

static void AepOta_ReqUpd_Init(void)
{
    memcpy(awaitUpdVer, sBackup.NewVerInfor.ver, 16);
    awaitUpdPackSize = OSAL_SWAP16(sBackup.NewVerInfor.singPackSize);
    awaitUpdPackNums = sBackup.ValidPackNums;
    UpdNextPackNum = sBackup.recvDataCount;
    UpdLastPackNum = UpdNextPackNum;
    TimerHandle_AepOtaReqUpd = OSAL_TimerCreate(AepOta_ReqUpd_TimeOut_Callback, 5000, SET);
}

static void ClearAepOtaMark_Callback(TimerHandle_stu_t xTimer)
{
    FUNC_NB_LOG_D("ClearAepOtaMark_Callback");
    SYS_CALL(NB_TASK_Set_AepOtaMark, RESET);
}
/**
 * @brief AEP 查询当前固件版本信息应答
 *
 * @note
 */
static void AepOta_QuerDeviceVer_Ack(void)
{
    uint8_t ver[32 + 1] = FIRMWARE_VER;
    AepOta_QuerDeviceVer_stu_t QuerDevVer = {0};
    QuerDevVer.result = 0;
    memcpy(QuerDevVer.ver, ver, 16);
    FUNC_NB_LOG_D("AepOta_QuerDevice Ver:%s", ver);
    NbMain_send_AepOtaData_to_NbIot(AEP_OTA_QUER_DEVICE_VER, sizeof(QuerDevVer), (uint8_t *)&QuerDevVer);
    // if (sBackup.status == AEP_OTA_STA_REP_UPD_RES)
    // {
    //     sBackup.status = AEP_OTA_STA_NONE;
    // }
    // else
    // {
    //     sBackup.status = AEP_OTA_STA_QUER_DEVICE_VER;
    SYS_CALL(NB_TASK_Set_AepOtaMark, SET);
    TimerHandle_ClearAepOtaMark = OSAL_TimerCreate(ClearAepOtaMark_Callback, 10000, RESET);
    // }
    // OSAL_NvWrite(SYS_OFFSET(aepOtaInfor), &sBackup, sizeof(sBackup));
}
/**
 * @brief AEP 上报升级结果
 *
 * @note
 */
static void AepOta_ReqUpdRes(void)
{
    AepOta_ReqUpdRes_stu_t sReqUpdRes = {0};
    sReqUpdRes.result = 0;
    memcpy(sReqUpdRes.ver, awaitUpdVer, 16);
    NbMain_send_AepOtaData_to_NbIot(AEP_OTA_REP_UPD_RES, sizeof(sReqUpdRes), (uint8_t *)&sReqUpdRes);
}

/**
 * @brief AEP 新版本通知
 *
 * @note
 */
static void AepOta_NewVerNotify_handle(uint8_t *pdata)
{
    OSAL_TimerDelete(TimerHandle_ClearAepOtaMark);
    AepOta_NewVerNotify_stu_t *pNewVerNotify = (AepOta_NewVerNotify_stu_t *)pdata;
    uint8_t result; // 0X00 允许升级  0X01设备使用中  0X02信号质量差  0X03已经是最新版本  0X04电量不足    0X05剩余空间不足    0X09内存不足    0X7F内部异常
    uint8_t ver[32 + 1] = FIRMWARE_VER;
    if (0 == memcmp(ver, pNewVerNotify->ver, 16))
    {
        result = AEP_OTA_VER_IS_NEV;
        NbMain_send_AepOtaData_to_NbIot(AEP_OTA_NEW_VER_NOTIFY, sizeof(result), &result);
        SYS_CALL(NB_TASK_Set_AepOtaMark, RESET);
        return;
    }
    else
    {
        result = 0;
        NbMain_send_AepOtaData_to_NbIot(AEP_OTA_NEW_VER_NOTIFY, sizeof(result), &result);
    }
    memcpy(awaitUpdVer, pNewVerNotify->ver, 16);
    awaitUpdPackSize = OSAL_SWAP16(pNewVerNotify->singPackSize);
    awaitUpdPackNums = OSAL_SWAP16(pNewVerNotify->PackNums);
    NB_TASK_LOG_E("NewVer:%s,singPackSize:%d,PackNums:%d", awaitUpdVer, awaitUpdPackSize, awaitUpdPackNums);

    if (0 == memcmp((uint8_t *)&sBackup.NewVerInfor, pdata, sizeof(AepOta_NewVerNotify_stu_t)) && sBackup.status == AEP_OTA_STA_DOWNLOADING)
    {
        UpdNextPackNum = sBackup.recvDataCount;
        awaitUpdPackNums = sBackup.ValidPackNums;
        FUNC_NB_LOG_D("AepOta start PackNum:%d", UpdNextPackNum);
    }
    else
    {
        FUNC_NB_LOG_D("AepOta find new code");
        //重新下载 先擦除整个备份区域
        SYS_CALL(McuOta_Task_EarseAllData);
        sBackup.ValidPackNums = awaitUpdPackNums;
        UpdNextPackNum = awaitUpdPackNums - 1;
        sBackup.recvDataCount = UpdNextPackNum;
        sBackup.status = AEP_OTA_STA_QUER_CODE_INFOR;
        sBackup.errCnt = 0;
        memcpy((uint8_t *)&sBackup.NewVerInfor, pdata, sizeof(AepOta_NewVerNotify_stu_t));
        AepOta_NvWrite();
    }
    SYS_CALL(NB_TASK_Set_AepOtaMark, SET);
    UpdLastPackNum = UpdNextPackNum;
    // AepOta_WtOffSet = UpdNextPackNum * awaitUpdPackSize;
    AepOta_ReqUpd_OnePack();
    TimerHandle_AepOtaReqUpd = OSAL_TimerCreate(AepOta_ReqUpd_TimeOut_Callback, 5000, SET);
}

/**
 * @brief AEP 得到一个升级包并请求下一个升级包
 *
 * @note
 */
static void AepOta_ReqUpd_handle(uint8_t *pdata)
{

    if (sBackup.status != AEP_OTA_STA_DOWNLOADING && sBackup.status != AEP_OTA_STA_QUER_CODE_INFOR)
        return;

    AepOta_ReqUpdPackInfor_stu_t *pInfor = (AepOta_ReqUpdPackInfor_stu_t *)pdata;
    if (UpdNextPackNum == OSAL_SWAP16(pInfor->PackNum))
    {
        AepOta_WtOffSet = awaitUpdPackSize * UpdNextPackNum;
        SYS_CALL(McuOta_Task_Write, AepOta_WtOffSet, pInfor->data, awaitUpdPackSize);
        UpdNextPackNum++;
        if (UpdNextPackNum % 16 == 0) //每4K保存一次断点
        {
            sBackup.recvDataCount = UpdNextPackNum;
            sBackup.errCnt = 0;
            AepOta_NvWrite();
            FUNC_NB_LOG_D("AepOta save DataCount:%d", UpdNextPackNum);
        }

        if (UpdNextPackNum == awaitUpdPackNums)
        {
            uint8_t result = AEP_OTA_CRC_ERR; // 上报升级包下载状态 0X00下载成功0X05剩余空间不足0X06下载超时0X07升级包校验失败0X08升级包类型不支持
            AepOta_sta_enum_stu_t status;
            if (sBackup.status == AEP_OTA_STA_QUER_CODE_INFOR) //获取固件信息成功
            {
                uint32_t reserved_num;
                UpdNextPackNum = 0;
                sBackup.recvDataCount = UpdNextPackNum;                         //断点保存为0
                memcpy((uint8_t *)&reserved_num, &pInfor->data[256 - 8], 4);    //获取0xff 的数量
                if (reserved_num < ((awaitUpdPackNums - 1) * awaitUpdPackSize)) //判断数据有效性
                {
                    awaitUpdPackNums = (awaitUpdPackNums * awaitUpdPackSize - reserved_num) / awaitUpdPackSize; //更新总包数 即 有效报数
                    sBackup.ValidPackNums = awaitUpdPackNums;                                                   //保存有效报数
                }
                AepOta_NvWrite();
                FUNC_NB_LOG_D("reserved_num:%d ValidPackNums: %d", reserved_num, sBackup.ValidPackNums);
                sBackup.status = AEP_OTA_STA_DOWNLOADING;
                AepOta_ReqUpd_OnePack();
                return;
            }
            else if (SUCCESS == SYS_CALL(McuOtaCode_Check) || TEST_AEP_OTA)
            {
                FUNC_NB_LOG_D("AEP OTA SUCC!!!");
                result = AEP_OTA_SUCCESS;
                status = AEP_OTA_STA_DOWNLOAD_OK;
            }
            else
            {
                FUNC_NB_LOG_D("AEP OTA Code Check err!!!");
                result = AEP_OTA_CRC_ERR;
                status = AEP_OTA_STA_NONE;
                SYS_CALL(NB_TASK_Set_AepOtaMark, RESET);
            }
            sBackup.recvDataCount = 0;
            sBackup.status = status;
            sBackup.errCnt = 0;
            AepOta_NvWrite();
            OSAL_TimerDelete(TimerHandle_AepOtaReqUpd);
            AepOta_generalAck_handle(AEP_OTA_REP_UPD_PACK_STA, result);
            return;
        }
        AepOta_ReqUpd_OnePack();
    }
}

/**
 * @brief AEP OTA数据处理
 *
 * @param [in] cmd
 * @param [in] pdata
 * @param [in] dataLen data的长度
 *
 * @note
 */
static void NbMain_ReceiveAepOtaCmd(uint8_t cmd, uint8_t *pdata, uint16_t dataLen)
{
    FUNC_NB_LOG_D("AepOta Cmd:%d,dataLen::%d", cmd, dataLen);
    // FUNC_NB_LOG_HEX("AepOta data", pdata, dataLen);
    switch (cmd)
    {
    case AEP_OTA_QUER_DEVICE_VER:                         // 19 查询设备版本
        AepOta_QuerDeviceVer_Ack();                       //
        break;                                            //
    case AEP_OTA_NEW_VER_NOTIFY:                          // 20 新版本通知
        AepOta_NewVerNotify_handle(pdata);                //
        break;                                            //
    case AEP_OTA_REQ_UPD:                                 // 21 请求升级包
        AepOta_ReqUpd_handle(pdata);                      //
        break;                                            //
    case AEP_OTA_REP_UPD_PACK_STA:                        // 22 上报升级包下载状态
        break;                                            //
    case AEP_OTA_PERFROM_UPD:                             // 23 执行升级 0X00处理成功0X01设备使用中0X04电量不足0X05剩余空间不足0X09内存不足
        AepOta_generalAck_handle(AEP_OTA_PERFROM_UPD, 0); //
        AepOta_ReqUpdRes();                               //
        sBackup.status = AEP_OTA_STA_NONE;                //
        sBackup.errCnt = 0;                               //
        SYS_CALL(NB_TASK_Set_AepOtaMark, RESET);          //
        AepOta_NvWrite();                                 //
        OSAL_SystemReset(2000);                           //
        SYS_CALL(Set_SilentRest_flag, SET);               //静默复位
        FUNC_NB_LOG_W("restart  time :%d", 2000);         //重启设备
        break;                                            //
    }
}

static void AepOta_Connect_init(void)
{
    switch (sBackup.status) //
    {
        // case AEP_OTA_STA_QUER_DEVICE_VER:                     //查询设备版本
        //     AepOta_QuerDeviceVer_Ack();                       //
        //     break;                                            //

    case AEP_OTA_STA_QUER_CODE_INFOR: // 请求固件信息
    case AEP_OTA_STA_DOWNLOADING:     // 固件下载中
    case AEP_OTA_STA_DOWNLOAD_OK:     // 固件下载完成
        AepOta_ReqUpd_Init();         //
        break;
        // case AEP_OTA_STA_REDAY_UPD:                           // 准备刷机
        //     AepOta_generalAck_handle(AEP_OTA_REP_UPD_RES, 0); //上报升级结果
        //     sBackup.status = AEP_OTA_STA_REP_UPD_RES;         //
        //     AepOta_NvWrite();                                 //
        //     break;                                            //
    }
}

/**
 * @brief 查询NB联网状态
 *
 * @param [in] xTimer
 *
 * @note
 */
static void AepOta_QueryNbConnectSta_Callback(TimerHandle_stu_t xTimer)
{
    static uint8_t cnt = 0;
    uint8_t nb_status = SYS_CALL(NB_TASK_get_nb_status);
    FUNC_NB_LOG_D("nb connect sta:%d", nb_status);
    if (nb_status < NB_STATUS_CONNECTED_AEP)
    {
        cnt++;
        OSAL_UpdateSleepTime(15000, 1);
        if (cnt > AEP_OTA_REQ_ONEPACK_MAX_TIME) //同一包数据请求最大次数,超过则暂停升级，让NB 模组休眠
        {
            cnt = 0;
            OSAL_TimerDelete(TimerHandle_QueryNbConnectSta);
            FUNC_NB_LOG_E("AepOta: NB connect AEP TimeOut");
        }
    }
    else
    {
        cnt = 0;
        OSAL_TimerDelete(TimerHandle_QueryNbConnectSta);
        FUNC_NB_LOG_D("AepOta: NB connect AEP succ OTA start");
        SYS_CALL(NB_TASK_Set_AepOtaMark, SET);
        if (nb_status != NB_STATUS_CONNECTED_AEP)
        {
            NBMain_control_nb_psm_status(NB_CONTROL_EXIT_PSM);
        }
        AepOta_Connect_init();
    }
}
/**
 * @brief AEP OTA 上电初始化
 *
 * @note
 */
static void AepOta_init(void)
{
    AepOta_NvRead(); //获取AEP OTA NV infor
    FUNC_NB_LOG_D("AepOta_init status:%d", sBackup.status);

    if (sBackup.status > AEP_OTA_STA_NONE)
    {
        TimerHandle_QueryNbConnectSta = OSAL_TimerCreate(AepOta_QueryNbConnectSta_Callback, 5000, SET);
    }
}
/**
 * @brief 产测上报4个码  SN  MAC  IMEI ICCID
 *
 *
 * @note
 */
static void NbMain_upd_FourID(void)
{
    uint8_t i;
    uint8_t ate[300] = {0};
    uint8_t sn[32 + 1] = {0};
    uint8_t mac[6 + 1] = {0};
    uint8_t imei[15 + 1] = {0};
    uint8_t iccid[20 + 1] = {0};
    uint8_t csq = 0;
    uint16_t len = 0;
    OSAL_NvRead(SYS_OFFSET(pcbaSn), sn, 32);
    OSAL_NvRead(SYS_OFFSET(bleMacAddr), mac, 6);
    OSAL_NvRead(SYS_OFFSET(nbIemi), imei, 15);
    OSAL_NvRead(SYS_OFFSET(nbIccid), iccid, 20);
    OSAL_NvRead(SYS_OFFSET(nbCSQ), &csq, 1);
    len += sprintf(ate + len, "SN:%s;", sn);
    len += sprintf(ate + len, "MAC:");
    for (i = 0; i < 6; i++)
        len += sprintf(ate + len, "%02X", mac[i]);
    len += sprintf(ate + len, ";");
    len += sprintf(ate + len, "IMEI:%s;", imei);
    len += sprintf(ate + len, "ICCID:%s;", iccid);
    len += sprintf(ate + len, "CSQ:%d\r\n", csq);

    FUNC_NB_LOG_I("ATE len:%d %s", len, ate);
    Nb_Send_ATE_ToNb(ate, len);
}
/**
 * @brief ATEP 数据处理
 *
 * @param [in] pdata
 * @param [in] dataLen data的长度
 *
 * @note
 */
static void NbMain_ReceiveATE_Cmd(uint8_t *pdata, uint16_t dataLen)
{
    FUNC_NB_LOG_D("ATE infor:%s", pdata);
    if (0 == memcmp(pdata, "M2SWRITE=MAC:", strlen("M2SWRITE=MAC:")))
    {
        if ((dataLen - strlen("M2SWRITE=MAC:")) == 12)
        {
            uint8_t mac[6] = {0};
            uint8_t active = 0;
            uint8_t ack[50] = {0};
            OSAL_NvWrite(SYS_OFFSET(lockActiveFlag), &active, 1); //重新烧录MAC 可以反激活
            SYS_CALL(NB_TASK_str_to_hex, pdata + strlen("M2SWRITE=MAC:"), mac, 12);
            NB_TASK_LOG_HEX("MAC", mac, 6);
            Ble_Set_MAC(mac);
            memcpy(ack, pdata + strlen("M2SWRITE="), 16);
            sprintf(ack + 16, "\r\n");
            Nb_Send_ATE_ToNb(ack, strlen(ack));
            OSAL_SystemReset(1000);
        }
        else
        {
            uint8_t tmp[] = {"ERR:length err"};
            Nb_Send_ATE_ToNb(tmp, strlen(tmp));
        }
    }
    else if (0 == memcmp(pdata, "M2SREAD=ALL?", strlen("M2SREAD=ALL?")))
    {
        uint8_t active = 0;
        OSAL_NvRead(SYS_OFFSET(lockActiveFlag), &active, 1);
        if (active == 1)
        {
            NbMain_upd_FourID();
        }
        else
        {
            getFourIdFlag = 1;
        }
    }
    else if (0 == memcmp(pdata, "M2SWRITE=SOFTREST", strlen("M2SWRITE=SOFTREST")))
    {
        OSAL_SystemReset(0);
    }
}
/**
 * @brief NB模组处理消息回调函数
 *
 * @param [in] msg
 * @param [in] len
 *
 * @note
 */
static void NbMain_message_Cb(void *msg, uint16_t len)
{
    NbPublishMsg_t *nb = (NbPublishMsg_t *)msg;
    uint8_t nbIemi[15 + 1] = {0};
    uint8_t active = 0;
    FUNC_NB_LOG_D("NbMain_message_Cb type:%d \r\n", nb->type);
    switch (nb->type)
    {
    case PUBLISH_APP_IMEI:

        OSAL_NvRead(SYS_OFFSET(nbIemi), nbIemi, 15);
        OSAL_NvRead(SYS_OFFSET(lockActiveFlag), &active, 1);
        if (active != 1)
        {
            OSAL_NvWrite(SYS_OFFSET(nbIemi), nb->pData, 15);
        }
        else if (memcmp(nbIemi, nb->pData, 15) != 0 || nb->len != 15)
        {
            FUNC_NB_LOG_E("nbIemi ERR len:%d nbIemi: %.*s", nb->len, 15, nb->pData);
            Beep_Set(0xff, 200); //当装锁时  发现前后板交叉连接时一直报警
        }
        break;
    case PUBLISH_APP_NB_DATA:
        NbMain_ReceiveNbCmd(nb->MID, nb->SID, nb->pData, nb->len);
        break;
    case PUBLISH_APP_CSQ:
        if (pGetCsqCallback != NULL)
        {
            pGetCsqCallback(nb->pData[0]);
            pGetCsqCallback = NULL;
        }
        OSAL_NvWrite(SYS_OFFSET(nbCSQ), nb->pData, 1);
        FUNC_NB_LOG_D("Received CSQ:%d", nb->pData[0]);
        break;
    case PUBLISH_APP_ICCID:
        OSAL_NvWrite(SYS_OFFSET(nbIccid), nb->pData, 20);
        FUNC_NB_LOG_D("iccid :%.*s", nb->len, nb->pData);
        break;
    case PUBLISH_APP_UE:
        memcpy(&nbUeParam, nb->pData, nb->len);
        FUNC_NB_LOG_D("cellId:%.*s", nbUeParam.cellIdLen, nbUeParam.cellId);
        FUNC_NB_LOG_D("DlEarfcn:%.*s", nbUeParam.dlEarfcnLen, nbUeParam.dlEarfcn);
        FUNC_NB_LOG_D("PCI:%.*s", nbUeParam.pciLen, nbUeParam.pci);
        FUNC_NB_LOG_D("RSRP:%.*s", nbUeParam.rsrpLen, nbUeParam.rsrp);
        FUNC_NB_LOG_D("SNR:%.*s", nbUeParam.snrLen, nbUeParam.snr);
        FUNC_NB_LOG_D("TxPower:%.*s", nbUeParam.txPowerLen, nbUeParam.txPower);
        break;

    case PUBLISH_APP_AEP_OTA:
        NbMain_ReceiveAepOtaCmd(nb->SID, nb->pData, nb->len);
        break;
    case PUBLISH_APP_ATE:
        NbMain_ReceiveATE_Cmd(nb->pData, nb->len);
        break;

    default:
        break;
    }
    OSAL_UpdateSleepTime(15000, 1);
}
/**
 * @brief RtcAlarm处理消息回调函数
 *
 * @param [in] msg
 * @param [in] len
 *
 * @note
 */
static void RtcAlarm_message_Cb(void *msg, uint16_t len)
{
    RtcAlarmInfor_stu_t *AlarmInfor = (RtcAlarmInfor_stu_t *)msg;
    SYS_CALL(Set_SilentRest_flag, SET); //静默唤醒
    NBMain_control_nb_psm_status(NB_CONTROL_EXIT_PSM);
    if (strcmp(HEART_BEAT_NAME, AlarmInfor->name) == 0)
    {
        FUNC_NB_LOG_D("Heart report");
        uint8_t period;
        OSAL_NvRead(SYS_OFFSET(heartBeatReportPeriod), &period, sizeof(period));
        FuncNb_lkm3_report_heartBeat_Handle(HEART_BEAT_TYPE_NATURAL, period, HEART_BEAT_START_TYPE_NATURAL);
    }
    else if (strcmp(RESTART_NAME, AlarmInfor->name) == 0)
    {
        FUNC_NB_LOG_D("restart");
        uint8_t period;
        OSAL_NvRead(SYS_OFFSET(restartDevicePeriod), &period, sizeof(period));
        FuncNb_lkm3_report_heartBeat_Handle(HEART_BEAT_TYPE_NATURAL, period, HEART_BEAT_START_TYPE_SOFT_RESTART);
    }
}
/**
 * @brief NB休眠回调函数
 * @note
 * @param
 * @retval ErrorStatus
 */
static ErrorStatus Nb_sleep_cb(void)
{
    FUNC_NB_LOG_I("Nb main sleep, nb status:%d\r\n", SYS_CALL(NB_TASK_get_nb_status));

#if (TEST_NB_RF)
    return ERROR;
#else
    TestMode_enum_t mode = TESTMODE_NORMAL;
    mode = ATE_GetProductionTestMode();

    if (SYS_CALL(NB_TASK_get_nb_status) != NB_STATUS_PSM)
    {
        if (SYS_CALL(NB_TASK_get_nb_status) == NB_STATUS_WAITPSM)
        {
            NBMain_control_nb_psm_status(NB_CONTROL_ENTER_PSM_NOT_RAI);
        }
        else
        {
            NBMain_control_nb_psm_status(NB_CONTROL_ENTER_PSM);
        }
        OSAL_UpdateSleepTime(3000, 1);
        return ERROR;
    }
    if ((mode != TESTMODE_NORMAL) && (get_sleep_flag() == 0))
    {
        FUNC_NB_LOG_I("Nb_sleep_cb NO SLEEP");
        return ERROR;
    }
    set_sleep_flag(0);
    return SUCCESS;
#endif
}

/**
 * @brief 上报 上电启动第一次心跳
 *
 *
 * @note
 */
static void NB_report_PowerOn_heart(void)
{
    uint8_t period;
    OSAL_NvRead(SYS_OFFSET(heartBeatReportPeriod), &period, sizeof(period));
    FuncNb_lkm3_report_heartBeat_Handle(HEART_BEAT_TYPE_NATURAL, period, HEART_BEAT_START_TYPE_POWER_ON);
}

/**
 * @brief  BLE APP启动函数
 * @note
 *
 * @param  wake_id：唤醒ID（组件ID），0XFF表示上电唤醒
 * @param  wake_param：唤醒参数
 */
static void NB_Main(uint32_t wake_id, uint32_t wake_param)
{
    FUNC_NB_LOG_I("Nb_main wake_id:%d, wake_param:%d\r\n", wake_id, wake_param);

    if (wake_id == 0xff)
    {
        NBMain_send_netInfo();
        Local_NvReset(0);
        NB_report_PowerOn_heart();
        // RtcAlarm_Set(RESTART_NAME, 60, SET);//测试设置心跳周期
    }
    AepOta_init();
    //上电唤醒：创建APP，订阅消息
    AppHandle_t app_handle = OSAL_AppCreate("NB_Main", Nb_sleep_cb);
    OSAL_MessageSubscribe(app_handle, COMP_NB, NbMain_message_Cb);
    OSAL_MessageSubscribe(app_handle, COMP_RTC, RtcAlarm_message_Cb);
    SYS_API(NbMain_send_readData_cmd);
    SYS_API(NbMain_get_CSQ);
    SYS_API(Remote_RecordReport);
}
APP_INIT_EXPORT(NB_Main);
